-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Preserve string delimiter in type printing. #60729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
2906dea
275f6b9
638ceea
b8d575a
1f2c52c
b983d7b
78f7c22
569b7ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1707,10 +1707,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind); | ||
| }, | ||
| typeToString: (type, enclosingDeclaration, flags) => { | ||
| return typeToString(type, getParseTreeNode(enclosingDeclaration), flags); | ||
| return typeToStringWorker(type, getParseTreeNode(enclosingDeclaration), flags); | ||
| }, | ||
| symbolToString: (symbol, enclosingDeclaration, meaning, flags) => { | ||
| return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags); | ||
| return symbolToStringWorker(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags); | ||
| }, | ||
| typePredicateToString: (predicate, enclosingDeclaration, flags) => { | ||
| return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags); | ||
|
|
@@ -1719,10 +1719,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind, writer); | ||
| }, | ||
| writeType: (type, enclosingDeclaration, flags, writer, verbosityLevel, out) => { | ||
| return typeToString(type, getParseTreeNode(enclosingDeclaration), flags, writer, verbosityLevel, out); | ||
| return typeToStringWorker(type, getParseTreeNode(enclosingDeclaration), flags, writer, verbosityLevel, out); | ||
| }, | ||
| writeSymbol: (symbol, enclosingDeclaration, meaning, flags, writer) => { | ||
| return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags, writer); | ||
| return symbolToStringWorker(symbol, getParseTreeNode(enclosingDeclaration), meaning, flags, writer); | ||
| }, | ||
| writeTypePredicate: (predicate, enclosingDeclaration, flags, writer) => { | ||
| return typePredicateToString(predicate, getParseTreeNode(enclosingDeclaration), flags, writer); | ||
|
|
@@ -5988,8 +5988,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| } | ||
|
|
||
| function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { | ||
| return symbolToStringWorker(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseDoubleQuotesForStringLiteralType, writer); | ||
| } | ||
| function symbolToStringWorker(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { | ||
| let nodeFlags = NodeBuilderFlags.IgnoreErrors; | ||
| let internalNodeFlags = InternalNodeBuilderFlags.None; | ||
| if (flags & SymbolFormatFlags.UseSingleQuotesForStringLiteralType) { | ||
| nodeFlags |= NodeBuilderFlags.UseSingleQuotesForStringLiteralType; | ||
| } | ||
| if (flags & SymbolFormatFlags.UseDoubleQuotesForStringLiteralType) { | ||
| nodeFlags |= NodeBuilderFlags.UseDoubleQuotesForStringLiteralType; | ||
| } | ||
| if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) { | ||
| nodeFlags |= NodeBuilderFlags.UseOnlyExternalAliasing; | ||
| } | ||
|
|
@@ -6039,13 +6048,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Prints a type, forcing the conversion of string delimiters to " | ||
| * This should usually be used for errors, since in errors printed types are inclosed in ' | ||
dragomirtitian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| */ | ||
| function typeToString( | ||
| type: Type, | ||
| enclosingDeclaration?: Node, | ||
| flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, | ||
| writer: EmitTextWriter = createTextWriter(""), | ||
| verbosityLevel?: number, | ||
| out?: WriterContextOut, | ||
| ): string { | ||
| return typeToStringWorker(type, enclosingDeclaration, flags | TypeFormatFlags.UseDoubleQuotesForStringLiteralType, writer, verbosityLevel, out); | ||
| } | ||
|
|
||
| function typeToStringWorker( | ||
| type: Type, | ||
| enclosingDeclaration?: Node, | ||
| flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, | ||
| writer: EmitTextWriter = createTextWriter(""), | ||
| verbosityLevel?: number, | ||
| out?: WriterContextOut, | ||
| ): string { | ||
| const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation || verbosityLevel !== undefined; | ||
| const typeNode = nodeBuilder.typeToTypeNode( | ||
|
|
@@ -6309,8 +6333,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| * It also calls `setOriginalNode` to setup a `.original` pointer, since you basically *always* want these in the node builder. | ||
| */ | ||
| function setTextRange<T extends Node>(context: NodeBuilderContext, range: T, location: Node | undefined): T { | ||
| if (!nodeIsSynthesized(range) || !(range.flags & NodeFlags.Synthesized) || !context.enclosingFile || context.enclosingFile !== getSourceFileOfNode(getOriginalNode(range))) { | ||
| range = factory.cloneNode(range); // if `range` is synthesized or originates in another file, copy it so it definitely has synthetic positions | ||
| const nodeSourceFile = getSourceFileOfNode(getOriginalNode(range)); | ||
| if (!nodeIsSynthesized(range) || !(range.flags & NodeFlags.Synthesized) || !context.enclosingFile || context.enclosingFile !== nodeSourceFile) { | ||
| if (range.kind === SyntaxKind.StringLiteral) { | ||
| const node = range as Node as StringLiteral; | ||
| return setOriginalNode( | ||
| context.flags & (NodeBuilderFlags.UseSingleQuotesForStringLiteralType | NodeBuilderFlags.UseDoubleQuotesForStringLiteralType) ? | ||
| factory.createStringLiteral(node.text, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)) : | ||
| factory.createStringLiteralFromNode(node), | ||
| node, | ||
| ) as Node as T; | ||
| } | ||
| else { | ||
| range = factory.cloneNode(range); // if `range` is synthesized or originates in another file, copy it so it definitely has synthetic positions | ||
| } | ||
| } | ||
| if (range === location) return range; | ||
| if (!location) { | ||
|
|
@@ -8516,10 +8552,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| } | ||
| let firstChar = symbolName.charCodeAt(0); | ||
|
|
||
| let useSingleQuote = !(context.flags & NodeBuilderFlags.UseDoubleQuotesForStringLiteralType) && | ||
| (!!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType) || firstChar === CharacterCodes.singleQuote); | ||
|
|
||
| if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { | ||
| return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context)); | ||
| return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context), useSingleQuote); | ||
| } | ||
| if (index === 0 || canUsePropertyAccess(symbolName, languageVersion)) { | ||
| if (canUsePropertyAccess(symbolName, languageVersion) || (index === 0 && firstChar === CharacterCodes.openBracket)) { | ||
| const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); | ||
| if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes)); | ||
| identifier.symbol = symbol; | ||
|
|
@@ -8530,21 +8569,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
| if (firstChar === CharacterCodes.openBracket) { | ||
| symbolName = symbolName.substring(1, symbolName.length - 1); | ||
| firstChar = symbolName.charCodeAt(0); | ||
| useSingleQuote = !(context.flags & NodeBuilderFlags.UseDoubleQuotesForStringLiteralType) && | ||
| (!!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType) || firstChar === CharacterCodes.singleQuote); | ||
| } | ||
| let expression: Expression | undefined; | ||
| if (isSingleOrDoubleQuote(firstChar) && !(symbol.flags & SymbolFlags.EnumMember)) { | ||
| expression = factory.createStringLiteral(stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), firstChar === CharacterCodes.singleQuote); | ||
| const stringLiteralName = factory.createStringLiteral(stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), useSingleQuote); | ||
| stringLiteralName.symbol = symbol; | ||
| expression = stringLiteralName; | ||
| } | ||
| else if (("" + +symbolName) === symbolName) { | ||
| expression = factory.createNumericLiteral(+symbolName); | ||
| const numberLiteralName = factory.createNumericLiteral(+symbolName); | ||
| numberLiteralName.symbol = symbol; | ||
| expression = numberLiteralName; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You probably want to use |
||
| } | ||
| if (!expression) { | ||
| const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); | ||
| if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes)); | ||
| identifier.symbol = symbol; | ||
| expression = identifier; | ||
| } | ||
| return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); | ||
| return index === 0 ? expression : factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -8572,7 +8617,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
|
|
||
| function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { | ||
| const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed); | ||
| const singleQuote = !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); | ||
| const singleQuote = context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType ? true : | ||
| context.flags & NodeBuilderFlags.UseDoubleQuotesForStringLiteralType ? false : | ||
| !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); | ||
| const isMethod = !!(symbol.flags & SymbolFlags.Method); | ||
| const fromNameType = getPropertyNameNodeForSymbolFromNameType(symbol, context, singleQuote, stringNamed, isMethod); | ||
| if (fromNameType) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ declare namespace demoNS { | |
| >f : Symbol(f, Decl(demo.d.ts, 0, 26)) | ||
| } | ||
| declare module 'demoModule' { | ||
| >'demoModule' : Symbol("demoModule", Decl(demo.d.ts, 2, 1)) | ||
| >'demoModule' : Symbol('demoModule', Decl(demo.d.ts, 2, 1)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised to see symbol baselines change; were we inconsistent with these before?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Symbol printing is involved in type printing and error printing. I applied the 'preserve source code delimiters in everything except errors' to the symbol printing too. This does mean that the delimiters are now preserved in symbol baselines where they previously were not. Were they always replaced before? Don't think so. Some error messages used symbol printing for the property names and we can see in error baselines changes that some of those kept the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I tried doing this in let symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent, undefined, ts.SymbolFormatFlags.AllowAnyNodeKind | ts.SymbolFormatFlags.UseDoubleQuotesForStringLiteralType);And it actually still changed a whole bunch of double quotes to single quotes.... Is there some place which is not respecting the flag?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the latest changes, the above seems to actually work, though I don't think I actually think it matters; preserving stuff seems reasonable enough. |
||
|
|
||
| import alias = demoNS; | ||
| >alias : Symbol(alias, Decl(demo.d.ts, 3, 29)) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.