diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80168823b3..fb1f62ddaf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -24752,7 +24752,11 @@ namespace ts { case SyntaxKind.ParenthesizedExpression: return evaluate((expr).expression); case SyntaxKind.Identifier: - return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), (expr).escapedText); + const identifier = expr; + if (isInfinityOrNaNString(identifier.escapedText)) { + return +(identifier.escapedText); + } + return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), identifier.escapedText); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: const ex = expr; @@ -27061,7 +27065,7 @@ namespace ts { } } - // We do global augmentations seperately from module augmentations (and before creating global types) because they + // We do global augmentations separately from module augmentations (and before creating global types) because they // 1. Affect global types. We won't have the correct global types until global augmentations are merged. Also, // 2. Module augmentation instantiation requires creating the type of a module, which, in turn, can require // checking for an export or property on the module (if export=) which, in turn, can fall back to the diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 90572217d4..cf07ee26b8 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2653,7 +2653,7 @@ namespace ts { /** * Matches any single directory segment unless it is the last segment and a .min.js file * Breakdown: - * [^./] # matches everything up to the first . character (excluding directory seperators) + * [^./] # matches everything up to the first . character (excluding directory separators) * (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension */ singleAsteriskRegexFragment: "([^./]|(\\.(?!min\\.js$))?)*", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b5cb450bfe..0e90e611d5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4281,16 +4281,20 @@ "category": "Message", "code": 95054 }, - "Add or remove braces in an arrow function": { + "Convert '{0}' to mapped object type": { "category": "Message", "code": 95055 }, - "Add braces to arrow function": { + "Add or remove braces in an arrow function": { "category": "Message", "code": 95056 }, - "Remove braces from arrow function": { + "Add braces to arrow function": { "category": "Message", "code": 95057 + }, + "Remove braces from arrow function": { + "category": "Message", + "code": 95058 } } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 9ed6b89ccc..9c4dfbe967 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1308,7 +1308,7 @@ namespace ts { let isPreviousTokenSeparator = false; while (true) { const ch = text.charCodeAt(pos); - // Numeric seperators are allowed anywhere within a numeric literal, except not at the beginning, or following another separator + // Numeric separators are allowed anywhere within a numeric literal, except not at the beginning, or following another separator if (ch === CharacterCodes._) { tokenFlags |= TokenFlags.ContainsSeparator; if (separatorAllowed) { diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 22b7f49670..01f99c4d6c 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -63,6 +63,7 @@ "../services/documentRegistry.ts", "../services/importTracker.ts", "../services/findAllReferences.ts", + "../services/getEditsForFileRename.ts", "../services/goToDefinition.ts", "../services/jsDoc.ts", "../services/semver.ts", @@ -118,6 +119,7 @@ "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", + "../services/codefixes/convertToMappedObjectType.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index f08745d21c..bbedf489c3 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1008,6 +1008,15 @@ + + + + + + + + + @@ -1125,6 +1134,15 @@ + + + + + + + + + @@ -6564,6 +6582,15 @@ + + + + + + + + + @@ -6603,6 +6630,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index e880c4493a..5604802bcb 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1019,10 +1019,13 @@ - + - + + + + @@ -1143,6 +1146,15 @@ + + + + + + + + + @@ -6582,6 +6594,15 @@ + + + + + + + + + @@ -6621,6 +6642,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index bdc5b984f4..5ec3b07f2e 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1007,6 +1007,15 @@ + + + + + + + + + @@ -1124,6 +1133,15 @@ + + + + + + + + + @@ -6563,6 +6581,15 @@ + + + + + + + + + @@ -6602,6 +6629,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index 6c5144093a..2bf08b16cc 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -59,6 +59,7 @@ "../services/documentRegistry.ts", "../services/importTracker.ts", "../services/findAllReferences.ts", + "../services/getEditsForFileRename.ts", "../services/goToDefinition.ts", "../services/jsDoc.ts", "../services/semver.ts", @@ -114,6 +115,7 @@ "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", + "../services/codefixes/convertToMappedObjectType.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", diff --git a/src/server/tsconfig.library.json b/src/server/tsconfig.library.json index 59ff8cc9e8..4217e3126b 100644 --- a/src/server/tsconfig.library.json +++ b/src/server/tsconfig.library.json @@ -65,6 +65,7 @@ "../services/documentRegistry.ts", "../services/importTracker.ts", "../services/findAllReferences.ts", + "../services/getEditsForFileRename.ts", "../services/goToDefinition.ts", "../services/jsDoc.ts", "../services/semver.ts", @@ -120,6 +121,7 @@ "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", + "../services/codefixes/convertToMappedObjectType.ts", "../services/refactors/extractSymbol.ts", "../services/refactors/generateGetAccessorAndSetAccessor.ts", "../services/refactors/moveToNewFile.ts", diff --git a/src/services/codefixes/convertToMappedObjectType.ts b/src/services/codefixes/convertToMappedObjectType.ts new file mode 100644 index 0000000000..ff86a9872b --- /dev/null +++ b/src/services/codefixes/convertToMappedObjectType.ts @@ -0,0 +1,56 @@ +/* @internal */ +namespace ts.codefix { + const fixIdAddMissingTypeof = "fixConvertToMappedObjectType"; + const fixId = fixIdAddMissingTypeof; + const errorCodes = [Diagnostics.An_index_signature_parameter_type_cannot_be_a_union_type_Consider_using_a_mapped_object_type_instead.code]; + + type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration; + + registerCodeFix({ + errorCodes, + getCodeActions: context => { + const { sourceFile, span } = context; + const info = getInfo(sourceFile, span.start); + if (!info) return undefined; + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); + const name = idText(info.container.name); + return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [Diagnostics.Convert_0_to_mapped_object_type, name])]; + }, + fixIds: [fixId], + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start); + if (info) doChange(changes, diag.file, info); + }) + }); + + interface Info { readonly indexSignature: IndexSignatureDeclaration; readonly container: FixableDeclaration; } + function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { + const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const indexSignature = cast(token.parent.parent, isIndexSignatureDeclaration); + if (isClassDeclaration(indexSignature.parent)) return undefined; + const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : cast(indexSignature.parent.parent, isTypeAliasDeclaration); + return { indexSignature, container }; + } + + function createTypeAliasFromInterface(declaration: FixableDeclaration, type: TypeNode): TypeAliasDeclaration { + return createTypeAliasDeclaration(declaration.decorators, declaration.modifiers, declaration.name, declaration.typeParameters, type); + } + + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { indexSignature, container }: Info): void { + const members = isInterfaceDeclaration(container) ? container.members : (container.type).members; + const otherMembers = members.filter(member => !isIndexSignatureDeclaration(member)); + const parameter = first(indexSignature.parameters); + const mappedTypeParameter = createTypeParameterDeclaration(cast(parameter.name, isIdentifier), parameter.type); + const mappedIntersectionType = createMappedTypeNode( + hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined, + mappedTypeParameter, + indexSignature.questionToken, + indexSignature.type); + const intersectionType = createIntersectionTypeNode([ + ...getAllSuperTypeNodes(container), + mappedIntersectionType, + ...(otherMembers.length ? [createTypeLiteralNode(otherMembers)] : emptyArray), + ]); + changes.replaceNode(sourceFile, container, createTypeAliasFromInterface(container, intersectionType)); + } +} diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 01fbc26403..cc526a53b1 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -211,7 +211,7 @@ namespace ts.codefix { // if this file doesn't have any import statements, insert an import statement and then insert a new line // between the only import statement and user code. Otherwise just insert the statement because chances - // are there are already a new line seperating code and import statements. + // are there are already a new line separating code and import statements. return createCodeAction(Diagnostics.Import_0_from_module_1, [symbolName, moduleSpecifierWithoutQuotes], changes); } diff --git a/src/services/completions.ts b/src/services/completions.ts index e703980676..56833298a6 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -422,7 +422,7 @@ namespace ts.Completions { case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(node.parent)) { - const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile); + const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile); // Get string literal completions from specialized signatures of the target // i.e. declare function f(a: 'A'); // f("/*completion position*/") @@ -452,7 +452,7 @@ namespace ts.Completions { } } - function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentListInfo, checker: TypeChecker): StringLiteralCompletionsFromTypes { + function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes { let isNewIdentifier = false; const uniques = createMap(); @@ -460,7 +460,7 @@ namespace ts.Completions { checker.getResolvedSignature(argumentInfo.invocation, candidates, argumentInfo.argumentCount); const types = flatMap(candidates, candidate => { if (!candidate.hasRestParameter && argumentInfo.argumentCount > candidate.parameters.length) return; - const type = checker.getParameterType(candidate, argumentInfo.argumentIndex!); // TODO: GH#18217 + const type = checker.getParameterType(candidate, argumentInfo.argumentIndex); isNewIdentifier = isNewIdentifier || !!(type.flags & TypeFlags.String); return getStringLiteralTypes(type, checker, uniques); }); @@ -720,10 +720,10 @@ namespace ts.Completions { case SyntaxKind.OpenBraceToken: return isJsxExpression(parent) && parent.parent.kind !== SyntaxKind.JsxElement ? checker.getContextualTypeForJsxAttribute(parent.parent) : undefined; default: - const argInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(currentToken, position, sourceFile); + const argInfo = SignatureHelp.getArgumentInfoForCompletions(currentToken, position, sourceFile); return argInfo // At `,`, treat this as the next argument after the comma. - ? checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex! + (currentToken.kind === SyntaxKind.CommaToken ? 1 : 0)) // TODO: GH#18217 + ? checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex + (currentToken.kind === SyntaxKind.CommaToken ? 1 : 0)) : isEqualityOperatorKind(currentToken.kind) && isBinaryExpression(parent) && isEqualityOperatorKind(parent.operatorToken.kind) // completion at `x ===/**/` should be for the right side ? checker.getTypeAtLocation(parent.left) diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index 7c71f9a6ed..1726f5e068 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -32,23 +32,20 @@ namespace ts { } function getImportsToUpdate(program: Program, oldFilePath: string, host: LanguageServiceHost): ReadonlyArray { - const checker = program.getTypeChecker(); const result: ToUpdate[] = []; for (const sourceFile of program.getSourceFiles()) { for (const ref of sourceFile.referencedFiles) { - if (!program.getSourceFileFromReference(sourceFile, ref) && resolveTripleslashReference(ref.fileName, sourceFile.fileName) === oldFilePath) { + if (resolveTripleslashReference(ref.fileName, sourceFile.fileName) === oldFilePath) { result.push({ sourceFile, toUpdate: ref }); } } for (const importStringLiteral of sourceFile.imports) { - // If it resolved to something already, ignore. - if (checker.getSymbolAtLocation(importStringLiteral)) continue; - const resolved = host.resolveModuleNames ? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName) : program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName); - if (resolved && contains(resolved.failedLookupLocations, oldFilePath)) { + // We may or may not have picked up on the file being renamed, so maybe successfully resolved to oldFilePath, or maybe that's in failedLookupLocations + if (resolved && contains(resolved.resolvedModule ? [resolved.resolvedModule.resolvedFileName] : resolved.failedLookupLocations, oldFilePath)) { result.push({ sourceFile, toUpdate: importStringLiteral }); } } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 75b96c48ca..f53b7ffad4 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -579,6 +579,9 @@ namespace ts.FindAllReferences { else if (isBinaryExpression(decl)) { // `module.exports = class {}` return Debug.assertDefined(decl.right.symbol); } + else if (isSourceFile(decl)) { // json module + return Debug.assertDefined(decl.symbol); + } return Debug.fail(); } diff --git a/src/services/pathCompletions.ts b/src/services/pathCompletions.ts index afa1d76bba..06cc7a7182 100644 --- a/src/services/pathCompletions.ts +++ b/src/services/pathCompletions.ts @@ -297,8 +297,8 @@ namespace ts.Completions.PathCompletions { // after the last '/' that appears in the fragment because that's where the replacement span // starts if (fragmentDirectory !== undefined) { - const moduleNameWithSeperator = ensureTrailingDirectorySeparator(fragmentDirectory); - return nonRelativeModuleNames.map(nonRelativeModuleName => removePrefix(nonRelativeModuleName, moduleNameWithSeperator)); + const moduleNameWithSeparator = ensureTrailingDirectorySeparator(fragmentDirectory); + return nonRelativeModuleNames.map(nonRelativeModuleName => removePrefix(nonRelativeModuleName, moduleNameWithSeparator)); } return nonRelativeModuleNames; } @@ -410,7 +410,7 @@ namespace ts.Completions.PathCompletions { return result; } - // Replace everything after the last directory seperator that appears + // Replace everything after the last directory separator that appears function getDirectoryFragmentTextSpan(text: string, textStart: number): TextSpan | undefined { const index = Math.max(text.lastIndexOf(directorySeparator), text.lastIndexOf("\\")); const offset = index !== -1 ? index + 1 : 0; diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index 6b49b84d4d..07104f8e62 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -88,7 +88,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { return { renameFilename, renameLocation, edits }; } - function isConvertableName (name: DeclarationName): name is AcceptedNameType { + function isConvertibleName (name: DeclarationName): name is AcceptedNameType { return isIdentifier(name) || isStringLiteral(name); } @@ -125,7 +125,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { // make sure declaration have AccessibilityModifier or Static Modifier or Readonly Modifier const meaning = ModifierFlags.AccessibilityModifier | ModifierFlags.Static | ModifierFlags.Readonly; if (!declaration || !rangeOverlapsWithStartEnd(declaration.name, startPosition, endPosition!) // TODO: GH#18217 - || !isConvertableName(declaration.name) || (getModifierFlags(declaration) | meaning) !== meaning) return undefined; + || !isConvertibleName(declaration.name) || (getModifierFlags(declaration) | meaning) !== meaning) return undefined; const name = declaration.name.text; const startWithUnderscore = startsWithUnderscore(name); diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 61330757f0..5fcf3e4866 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -1,17 +1,20 @@ /* @internal */ namespace ts.SignatureHelp { - export const enum ArgumentListKind { + const enum ArgumentListKind { TypeArguments, CallArguments, TaggedTemplateArguments, JSXAttributesArguments } - export interface ArgumentListInfo { + const enum InvocationKind { Call, TypeArgs } + type Invocation = { kind: InvocationKind.Call, node: CallLikeExpression } | { kind: InvocationKind.TypeArgs, called: Expression }; + + interface ArgumentListInfo { kind: ArgumentListKind; - invocation: CallLikeExpression; + invocation: Invocation; argumentsSpan: TextSpan; - argumentIndex?: number; + argumentIndex: number; /** argumentCount is the *apparent* number of arguments. */ argumentCount: number; } @@ -32,32 +35,39 @@ namespace ts.SignatureHelp { cancellationToken.throwIfCancellationRequested(); // Semantic filtering of signature help - const call = argumentInfo.invocation; - const candidates: Signature[] = []; - const resolvedSignature = typeChecker.getResolvedSignature(call, candidates, argumentInfo.argumentCount); + const candidateInfo = getCandidateInfo(argumentInfo, typeChecker); cancellationToken.throwIfCancellationRequested(); - if (!candidates.length) { + if (!candidateInfo) { // We didn't have any sig help items produced by the TS compiler. If this is a JS // file, then see if we can figure out anything better. if (isSourceFileJavaScript(sourceFile)) { return createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken); } - return undefined; } - return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidates, resolvedSignature!, argumentInfo, typeChecker)); + return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker)); + } + + function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker): { readonly candidates: ReadonlyArray, readonly resolvedSignature: Signature } | undefined { + const { invocation } = argumentInfo; + if (invocation.kind === InvocationKind.Call) { + const candidates: Signature[] = []; + const resolvedSignature = checker.getResolvedSignature(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217 + return candidates.length === 0 ? undefined : { candidates, resolvedSignature }; + } + else { + const type = checker.getTypeAtLocation(invocation.called)!; // TODO: GH#18217 + const signatures = isNewExpression(invocation.called.parent) ? type.getConstructSignatures() : type.getCallSignatures(); + const candidates = signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= argumentInfo.argumentCount); + return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) }; + } } function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined { - if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) { - return undefined; - } - // See if we can find some symbol with the call expression name that has call signatures. - const callExpression = argumentInfo.invocation; - const expression = callExpression.expression; + const expression = getExpressionFromInvocation(argumentInfo.invocation); const name = isIdentifier(expression) ? expression : isPropertyAccessExpression(expression) ? expression.name : undefined; if (!name || !name.escapedText) { return undefined; @@ -76,7 +86,7 @@ namespace ts.SignatureHelp { if (type) { const callSignatures = type.getCallSignatures(); if (callSignatures && callSignatures.length) { - return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo, typeChecker)); + return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo, sourceFile, typeChecker)); } } } @@ -85,13 +95,25 @@ namespace ts.SignatureHelp { } } + export interface ArgumentInfoForCompletions { + readonly invocation: CallLikeExpression; + readonly argumentIndex: number; + readonly argumentCount: number; + } + export function getArgumentInfoForCompletions(node: Node, position: number, sourceFile: SourceFile): ArgumentInfoForCompletions | undefined { + const info = getImmediatelyContainingArgumentInfo(node, position, sourceFile); + return !info || info.kind === ArgumentListKind.TypeArguments || info.invocation.kind === InvocationKind.TypeArgs ? undefined + : { invocation: info.invocation.node, argumentCount: info.argumentCount, argumentIndex: info.argumentIndex }; + } + /** * Returns relevant information for the argument list and the current argument if we are * in the argument of an invocation; returns undefined otherwise. */ - export function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined { + function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined { const { parent } = node; if (isCallOrNewExpression(parent)) { + const invocation = parent; let list: Node | undefined; let argumentIndex: number; @@ -134,56 +156,63 @@ namespace ts.SignatureHelp { Debug.assertLessThan(argumentIndex, argumentCount); } const argumentsSpan = getApplicableSpanForArguments(list, sourceFile); - return { kind, invocation: parent, argumentsSpan, argumentIndex, argumentCount }; + return { kind, invocation: { kind: InvocationKind.Call, node: invocation }, argumentsSpan, argumentIndex, argumentCount }; } - else if (node.kind === SyntaxKind.NoSubstitutionTemplateLiteral && parent.kind === SyntaxKind.TaggedTemplateExpression) { + else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) { // Check if we're actually inside the template; // otherwise we'll fall out and return undefined. - if (isInsideTemplateLiteral(node, position)) { - return getArgumentListInfoForTemplate(node.parent, /*argumentIndex*/ 0, sourceFile); + if (isInsideTemplateLiteral(node, position)) { + return getArgumentListInfoForTemplate(parent, /*argumentIndex*/ 0, sourceFile); } } - else if (node.kind === SyntaxKind.TemplateHead && parent.parent.kind === SyntaxKind.TaggedTemplateExpression) { - const templateExpression = node.parent; + else if (isTemplateHead(node) && parent.parent.kind === SyntaxKind.TaggedTemplateExpression) { + const templateExpression = parent; const tagExpression = templateExpression.parent; Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression); - const argumentIndex = isInsideTemplateLiteral(node, position) ? 0 : 1; + const argumentIndex = isInsideTemplateLiteral(node, position) ? 0 : 1; return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile); } - else if (parent.kind === SyntaxKind.TemplateSpan && parent.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) { - const templateSpan = node.parent; - const templateExpression = templateSpan.parent; - const tagExpression = templateExpression.parent; - Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression); + else if (isTemplateSpan(parent) && isTaggedTemplateExpression(parent.parent.parent)) { + const templateSpan = parent; + const tagExpression = parent.parent.parent; // If we're just after a template tail, don't show signature help. if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(node, position)) { return undefined; } - const spanIndex = templateExpression.templateSpans.indexOf(templateSpan); + const spanIndex = templateSpan.parent.templateSpans.indexOf(templateSpan); const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position); return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile); } - else if (node.parent && isJsxOpeningLikeElement(node.parent)) { + else if (isJsxOpeningLikeElement(parent)) { // Provide a signature help for JSX opening element or JSX self-closing element. // This is not guarantee that JSX tag-name is resolved into stateless function component. (that is done in "getSignatureHelpItems") // i.e // export function MainButton(props: ButtonProps, context: any): JSX.Element { ... } // n.parent.end) { - Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind); - } - + Debug.assert(rangeContainsRange(n.parent, n), "Not a subspan", () => `Child: ${Debug.showSyntaxKind(n)}, parent: ${Debug.showSyntaxKind(n.parent)}`); const argumentInfo = getImmediatelyContainingArgumentInfo(n, position, sourceFile); if (argumentInfo) { return argumentInfo; } - - - // TODO: Handle generic call with incomplete syntax } return undefined; } @@ -343,16 +362,20 @@ namespace ts.SignatureHelp { return children[indexOfOpenerToken + 1]; } + function getExpressionFromInvocation(invocation: Invocation): Expression { + return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called; + } + const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors; - function createSignatureHelpItems(candidates: Signature[], resolvedSignature: Signature, argumentListInfo: ArgumentListInfo, typeChecker: TypeChecker): SignatureHelpItems { + function createSignatureHelpItems(candidates: ReadonlyArray, resolvedSignature: Signature, argumentListInfo: ArgumentListInfo, sourceFile: SourceFile, typeChecker: TypeChecker): SignatureHelpItems { const { argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex } = argumentListInfo; const isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments; - const callTarget = getInvokedExpression(invocation); - const callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget); + const enclosingDeclaration = invocation.kind === InvocationKind.Call ? invocation.node : invocation.called; + const callTargetSymbol = typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation)); const callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); const printer = createPrinter({ removeComments: true }); - const items: SignatureHelpItem[] = map(candidates, candidateSignature => { + const items = candidates.map(candidateSignature => { let signatureHelpParameters: SignatureHelpParameter[]; const prefixDisplayParts: SymbolDisplayPart[] = []; const suffixDisplayParts: SymbolDisplayPart[] = []; @@ -369,9 +392,9 @@ namespace ts.SignatureHelp { signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); const parameterParts = mapToDisplayParts(writer => { - const thisParameter = candidateSignature.thisParameter ? [typeChecker.symbolToParameterDeclaration(candidateSignature.thisParameter, invocation, signatureHelpNodeBuilderFlags)!] : []; - const params = createNodeArray([...thisParameter, ...map(candidateSignature.parameters, param => typeChecker.symbolToParameterDeclaration(param, invocation, signatureHelpNodeBuilderFlags)!)]); - printer.writeList(ListFormat.CallExpressionArguments, params, getSourceFileOfNode(getParseTreeNode(invocation)), writer); + const thisParameter = candidateSignature.thisParameter ? [typeChecker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : []; + const params = createNodeArray([...thisParameter, ...candidateSignature.parameters.map(param => typeChecker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]); + printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer); }); addRange(suffixDisplayParts, parameterParts); } @@ -379,8 +402,8 @@ namespace ts.SignatureHelp { isVariadic = candidateSignature.hasRestParameter; const typeParameterParts = mapToDisplayParts(writer => { if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { - const args = createNodeArray(map(candidateSignature.typeParameters, p => typeChecker.typeParameterToDeclaration(p, invocation)!)); - printer.writeList(ListFormat.TypeParameters, args, getSourceFileOfNode(getParseTreeNode(invocation)), writer); + const args = createNodeArray(candidateSignature.typeParameters.map(p => typeChecker.typeParameterToDeclaration(p, enclosingDeclaration)!)); + printer.writeList(ListFormat.TypeParameters, args, sourceFile, writer); } }); addRange(prefixDisplayParts, typeParameterParts); @@ -395,10 +418,10 @@ namespace ts.SignatureHelp { writer.writeSpace(" "); const predicate = typeChecker.getTypePredicateOfSignature(candidateSignature); if (predicate) { - typeChecker.writeTypePredicate(predicate, invocation, /*flags*/ undefined, writer); + typeChecker.writeTypePredicate(predicate, enclosingDeclaration, /*flags*/ undefined, writer); } else { - typeChecker.writeType(typeChecker.getReturnTypeOfSignature(candidateSignature), invocation, /*flags*/ undefined, writer); + typeChecker.writeType(typeChecker.getReturnTypeOfSignature(candidateSignature), enclosingDeclaration, /*flags*/ undefined, writer); } }); addRange(suffixDisplayParts, returnTypeParts); @@ -415,18 +438,18 @@ namespace ts.SignatureHelp { }); if (argumentIndex !== 0) { - Debug.assertLessThan(argumentIndex!, argumentCount); // TODO: GH#18217 + Debug.assertLessThan(argumentIndex, argumentCount); } const selectedItemIndex = candidates.indexOf(resolvedSignature); Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function. - return { items, applicableSpan, selectedItemIndex, argumentIndex: argumentIndex!, argumentCount }; // TODO: GH#18217 + return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = typeChecker.symbolToParameterDeclaration(parameter, invocation, signatureHelpNodeBuilderFlags)!; - printer.writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(invocation)), writer); + const param = typeChecker.symbolToParameterDeclaration(parameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; + printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); return { @@ -439,8 +462,8 @@ namespace ts.SignatureHelp { function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = typeChecker.typeParameterToDeclaration(typeParameter, invocation)!; - printer.writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(invocation)), writer); + const param = typeChecker.typeParameterToDeclaration(typeParameter, enclosingDeclaration)!; + printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); return { diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 4d94facef3..2ee70d03a6 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -56,6 +56,7 @@ "documentRegistry.ts", "importTracker.ts", "findAllReferences.ts", + "getEditsForFileRename.ts", "goToDefinition.ts", "jsDoc.ts", "semver.ts", @@ -111,6 +112,7 @@ "codefixes/requireInTs.ts", "codefixes/useDefaultImport.ts", "codefixes/fixAddModuleReferTypeMissingTypeof.ts", + "codefixes/convertToMappedObjectType.ts", "refactors/extractSymbol.ts", "refactors/generateGetAccessorAndSetAccessor.ts", "refactors/moveToNewFile.ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 535f35eb48..199ef0fea9 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -920,7 +920,11 @@ namespace ts { } } - export function isPossiblyTypeArgumentPosition(tokenIn: Node, sourceFile: SourceFile): boolean { + export interface PossibleTypeArgumentInfo { + readonly called: Identifier; + readonly nTypeArguments: number; + } + export function isPossiblyTypeArgumentPosition(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined { let token: Node | undefined = tokenIn; // This function determines if the node could be type argument position // Since during editing, when type argument list is not complete, @@ -928,15 +932,15 @@ namespace ts { // scanning of the previous identifier followed by "<" before current node would give us better result // Note that we also balance out the already provided type arguments, arrays, object literals while doing so let remainingLessThanTokens = 0; + let nTypeArguments = 0; while (token) { switch (token.kind) { case SyntaxKind.LessThanToken: // Found the beginning of the generic argument expression token = findPrecedingToken(token.getFullStart(), sourceFile); - if (!token) return false; - const tokenIsIdentifier = isIdentifier(token); - if (!remainingLessThanTokens || !tokenIsIdentifier) { - return tokenIsIdentifier; + if (!token || !isIdentifier(token)) return undefined; + if (!remainingLessThanTokens) { + return { called: token, nTypeArguments }; } remainingLessThanTokens--; break; @@ -957,25 +961,28 @@ namespace ts { // This can be object type, skip until we find the matching open brace token // Skip until the matching open brace token token = findPrecedingMatchingToken(token, SyntaxKind.OpenBraceToken, sourceFile); - if (!token) return false; + if (!token) return undefined; break; case SyntaxKind.CloseParenToken: // This can be object type, skip until we find the matching open brace token // Skip until the matching open brace token token = findPrecedingMatchingToken(token, SyntaxKind.OpenParenToken, sourceFile); - if (!token) return false; + if (!token) return undefined; break; case SyntaxKind.CloseBracketToken: // This can be object type, skip until we find the matching open brace token // Skip until the matching open brace token token = findPrecedingMatchingToken(token, SyntaxKind.OpenBracketToken, sourceFile); - if (!token) return false; + if (!token) return undefined; break; // Valid tokens in a type name. Skip. case SyntaxKind.CommaToken: + nTypeArguments++; + break; + case SyntaxKind.EqualsGreaterThanToken: case SyntaxKind.Identifier: @@ -999,13 +1006,13 @@ namespace ts { } // Invalid token in type - return false; + return undefined; } token = findPrecedingToken(token.getFullStart(), sourceFile); } - return false; + return undefined; } /** @@ -1086,7 +1093,7 @@ namespace ts { return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation; } - export function isInsideTemplateLiteral(node: LiteralExpression, position: number) { + export function isInsideTemplateLiteral(node: LiteralExpression | TemplateHead, position: number) { return isTemplateLiteralKind(node.kind) && (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd()); } diff --git a/tests/baselines/reference/enumConstantMembers.errors.txt b/tests/baselines/reference/enumConstantMembers.errors.txt new file mode 100644 index 0000000000..446f09040f --- /dev/null +++ b/tests/baselines/reference/enumConstantMembers.errors.txt @@ -0,0 +1,64 @@ +tests/cases/conformance/enums/enumConstantMembers.ts(32,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/conformance/enums/enumConstantMembers.ts(33,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/conformance/enums/enumConstantMembers.ts(34,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/conformance/enums/enumConstantMembers.ts(35,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. +tests/cases/conformance/enums/enumConstantMembers.ts(36,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. +tests/cases/conformance/enums/enumConstantMembers.ts(37,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/conformance/enums/enumConstantMembers.ts(38,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + + +==== tests/cases/conformance/enums/enumConstantMembers.ts (7 errors) ==== + // Constant members allow negatives, but not decimals. Also hex literals are allowed + enum E1 { + a = 1, + b + } + enum E2 { + a = - 1, + b + } + enum E3 { + a = 0.1, + b // Error because 0.1 is not a constant + } + + declare enum E4 { + a = 1, + b = -1, + c = 0.1 // Not a constant + } + + enum E5 { + a = 1 / 0, + b = 2 / 0.0, + c = 1.0 / 0.0, + d = 0.0 / 0.0, + e = NaN, + f = Infinity, + g = -Infinity + } + + const enum E6 { + a = 1 / 0, + ~~~~~ +!!! error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + b = 2 / 0.0, + ~~~~~~~ +!!! error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + c = 1.0 / 0.0, + ~~~~~~~~~ +!!! error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + d = 0.0 / 0.0, + ~~~~~~~~~ +!!! error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. + e = NaN, + ~~~ +!!! error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. + f = Infinity, + ~~~~~~~~ +!!! error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + g = -Infinity + ~~~~~~~~~ +!!! error TS2477: 'const' enum member initializer was evaluated to a non-finite value. + } + \ No newline at end of file diff --git a/tests/baselines/reference/enumConstantMembers.js b/tests/baselines/reference/enumConstantMembers.js index f58c7d253a..a74d057063 100644 --- a/tests/baselines/reference/enumConstantMembers.js +++ b/tests/baselines/reference/enumConstantMembers.js @@ -17,7 +17,28 @@ declare enum E4 { a = 1, b = -1, c = 0.1 // Not a constant -} +} + +enum E5 { + a = 1 / 0, + b = 2 / 0.0, + c = 1.0 / 0.0, + d = 0.0 / 0.0, + e = NaN, + f = Infinity, + g = -Infinity +} + +const enum E6 { + a = 1 / 0, + b = 2 / 0.0, + c = 1.0 / 0.0, + d = 0.0 / 0.0, + e = NaN, + f = Infinity, + g = -Infinity +} + //// [enumConstantMembers.js] // Constant members allow negatives, but not decimals. Also hex literals are allowed @@ -36,3 +57,13 @@ var E3; E3[E3["a"] = 0.1] = "a"; E3[E3["b"] = 1.1] = "b"; // Error because 0.1 is not a constant })(E3 || (E3 = {})); +var E5; +(function (E5) { + E5[E5["a"] = Infinity] = "a"; + E5[E5["b"] = Infinity] = "b"; + E5[E5["c"] = Infinity] = "c"; + E5[E5["d"] = NaN] = "d"; + E5[E5["e"] = NaN] = "e"; + E5[E5["f"] = Infinity] = "f"; + E5[E5["g"] = -Infinity] = "g"; +})(E5 || (E5 = {})); diff --git a/tests/baselines/reference/enumConstantMembers.symbols b/tests/baselines/reference/enumConstantMembers.symbols index 6bf516ccee..54a62d8911 100644 --- a/tests/baselines/reference/enumConstantMembers.symbols +++ b/tests/baselines/reference/enumConstantMembers.symbols @@ -40,3 +40,60 @@ declare enum E4 { c = 0.1 // Not a constant >c : Symbol(E4.c, Decl(enumConstantMembers.ts, 16, 11)) } + +enum E5 { +>E5 : Symbol(E5, Decl(enumConstantMembers.ts, 18, 1)) + + a = 1 / 0, +>a : Symbol(E5.a, Decl(enumConstantMembers.ts, 20, 9)) + + b = 2 / 0.0, +>b : Symbol(E5.b, Decl(enumConstantMembers.ts, 21, 14)) + + c = 1.0 / 0.0, +>c : Symbol(E5.c, Decl(enumConstantMembers.ts, 22, 16)) + + d = 0.0 / 0.0, +>d : Symbol(E5.d, Decl(enumConstantMembers.ts, 23, 18)) + + e = NaN, +>e : Symbol(E5.e, Decl(enumConstantMembers.ts, 24, 18)) +>NaN : Symbol(NaN, Decl(lib.d.ts, --, --)) + + f = Infinity, +>f : Symbol(E5.f, Decl(enumConstantMembers.ts, 25, 12)) +>Infinity : Symbol(Infinity, Decl(lib.d.ts, --, --)) + + g = -Infinity +>g : Symbol(E5.g, Decl(enumConstantMembers.ts, 26, 17)) +>Infinity : Symbol(Infinity, Decl(lib.d.ts, --, --)) +} + +const enum E6 { +>E6 : Symbol(E6, Decl(enumConstantMembers.ts, 28, 1)) + + a = 1 / 0, +>a : Symbol(E6.a, Decl(enumConstantMembers.ts, 30, 15)) + + b = 2 / 0.0, +>b : Symbol(E6.b, Decl(enumConstantMembers.ts, 31, 14)) + + c = 1.0 / 0.0, +>c : Symbol(E6.c, Decl(enumConstantMembers.ts, 32, 16)) + + d = 0.0 / 0.0, +>d : Symbol(E6.d, Decl(enumConstantMembers.ts, 33, 18)) + + e = NaN, +>e : Symbol(E6.e, Decl(enumConstantMembers.ts, 34, 18)) +>NaN : Symbol(NaN, Decl(lib.d.ts, --, --)) + + f = Infinity, +>f : Symbol(E6.f, Decl(enumConstantMembers.ts, 35, 12)) +>Infinity : Symbol(Infinity, Decl(lib.d.ts, --, --)) + + g = -Infinity +>g : Symbol(E6.g, Decl(enumConstantMembers.ts, 36, 17)) +>Infinity : Symbol(Infinity, Decl(lib.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/enumConstantMembers.types b/tests/baselines/reference/enumConstantMembers.types index bfbf71a6c1..0015a6debb 100644 --- a/tests/baselines/reference/enumConstantMembers.types +++ b/tests/baselines/reference/enumConstantMembers.types @@ -48,3 +48,86 @@ declare enum E4 { >c : E4.c >0.1 : 0.1 } + +enum E5 { +>E5 : E5 + + a = 1 / 0, +>a : E5 +>1 / 0 : number +>1 : 1 +>0 : 0 + + b = 2 / 0.0, +>b : E5 +>2 / 0.0 : number +>2 : 2 +>0.0 : 0 + + c = 1.0 / 0.0, +>c : E5 +>1.0 / 0.0 : number +>1.0 : 1 +>0.0 : 0 + + d = 0.0 / 0.0, +>d : E5 +>0.0 / 0.0 : number +>0.0 : 0 +>0.0 : 0 + + e = NaN, +>e : E5 +>NaN : number + + f = Infinity, +>f : E5 +>Infinity : number + + g = -Infinity +>g : E5 +>-Infinity : number +>Infinity : number +} + +const enum E6 { +>E6 : E6 + + a = 1 / 0, +>a : E6 +>1 / 0 : number +>1 : 1 +>0 : 0 + + b = 2 / 0.0, +>b : E6 +>2 / 0.0 : number +>2 : 2 +>0.0 : 0 + + c = 1.0 / 0.0, +>c : E6 +>1.0 / 0.0 : number +>1.0 : 1 +>0.0 : 0 + + d = 0.0 / 0.0, +>d : E6 +>0.0 / 0.0 : number +>0.0 : 0 +>0.0 : 0 + + e = NaN, +>e : E6 +>NaN : number + + f = Infinity, +>f : E6 +>Infinity : number + + g = -Infinity +>g : E6 +>-Infinity : number +>Infinity : number +} + diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNew.errors.txt b/tests/baselines/reference/parseCommaSeparatedNewlineNew.errors.txt similarity index 56% rename from tests/baselines/reference/parseCommaSeperatedNewlineNew.errors.txt rename to tests/baselines/reference/parseCommaSeparatedNewlineNew.errors.txt index ff3ff1a033..6b779e15da 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNew.errors.txt +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNew.errors.txt @@ -1,9 +1,9 @@ -tests/cases/compiler/parseCommaSeperatedNewlineNew.ts(1,2): error TS2304: Cannot find name 'a'. -tests/cases/compiler/parseCommaSeperatedNewlineNew.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. -tests/cases/compiler/parseCommaSeperatedNewlineNew.ts(2,4): error TS1109: Expression expected. +tests/cases/compiler/parseCommaSeparatedNewlineNew.ts(1,2): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parseCommaSeparatedNewlineNew.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. +tests/cases/compiler/parseCommaSeparatedNewlineNew.ts(2,4): error TS1109: Expression expected. -==== tests/cases/compiler/parseCommaSeperatedNewlineNew.ts (3 errors) ==== +==== tests/cases/compiler/parseCommaSeparatedNewlineNew.ts (3 errors) ==== (a, ~ !!! error TS2304: Cannot find name 'a'. diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineNew.js b/tests/baselines/reference/parseCommaSeparatedNewlineNew.js new file mode 100644 index 0000000000..04ef5d6e73 --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNew.js @@ -0,0 +1,7 @@ +//// [parseCommaSeparatedNewlineNew.ts] +(a, +new) + +//// [parseCommaSeparatedNewlineNew.js] +(a, + new ); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNew.symbols b/tests/baselines/reference/parseCommaSeparatedNewlineNew.symbols similarity index 54% rename from tests/baselines/reference/parseCommaSeperatedNewlineNew.symbols rename to tests/baselines/reference/parseCommaSeparatedNewlineNew.symbols index 757444b907..d912adbb5e 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNew.symbols +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNew.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineNew.ts === +=== tests/cases/compiler/parseCommaSeparatedNewlineNew.ts === (a, No type information for this code.new) No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineNew.types b/tests/baselines/reference/parseCommaSeparatedNewlineNew.types new file mode 100644 index 0000000000..d787e88984 --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNew.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/parseCommaSeparatedNewlineNew.ts === +(a, +>(a,new) : any +>a,new : any +>a : any + +new) +>new : any +> : any + diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.errors.txt b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.errors.txt similarity index 57% rename from tests/baselines/reference/parseCommaSeperatedNewlineNumber.errors.txt rename to tests/baselines/reference/parseCommaSeparatedNewlineNumber.errors.txt index 73f087cc1e..f059aaf633 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.errors.txt +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.errors.txt @@ -1,8 +1,8 @@ -tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts(1,2): error TS2304: Cannot find name 'a'. -tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. +tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts(1,2): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. -==== tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts (2 errors) ==== +==== tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts (2 errors) ==== (a, ~ !!! error TS2304: Cannot find name 'a'. diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineNumber.js b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.js new file mode 100644 index 0000000000..3105c4258e --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.js @@ -0,0 +1,7 @@ +//// [parseCommaSeparatedNewlineNumber.ts] +(a, +1) + +//// [parseCommaSeparatedNewlineNumber.js] +(a, + 1); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.symbols b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.symbols similarity index 53% rename from tests/baselines/reference/parseCommaSeperatedNewlineNumber.symbols rename to tests/baselines/reference/parseCommaSeparatedNewlineNumber.symbols index 6fca007a89..2775ffef17 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.symbols +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts === +=== tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts === (a, No type information for this code.1) No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineNumber.types b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.types new file mode 100644 index 0000000000..a6f107bbd4 --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineNumber.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts === +(a, +>(a,1) : 1 +>a,1 : 1 +>a : any + +1) +>1 : 1 + diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineString.errors.txt b/tests/baselines/reference/parseCommaSeparatedNewlineString.errors.txt similarity index 57% rename from tests/baselines/reference/parseCommaSeperatedNewlineString.errors.txt rename to tests/baselines/reference/parseCommaSeparatedNewlineString.errors.txt index 2c70bfbfc3..d8e7d5efc7 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineString.errors.txt +++ b/tests/baselines/reference/parseCommaSeparatedNewlineString.errors.txt @@ -1,8 +1,8 @@ -tests/cases/compiler/parseCommaSeperatedNewlineString.ts(1,2): error TS2304: Cannot find name 'a'. -tests/cases/compiler/parseCommaSeperatedNewlineString.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. +tests/cases/compiler/parseCommaSeparatedNewlineString.ts(1,2): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parseCommaSeparatedNewlineString.ts(1,2): error TS2695: Left side of comma operator is unused and has no side effects. -==== tests/cases/compiler/parseCommaSeperatedNewlineString.ts (2 errors) ==== +==== tests/cases/compiler/parseCommaSeparatedNewlineString.ts (2 errors) ==== (a, ~ !!! error TS2304: Cannot find name 'a'. diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineString.js b/tests/baselines/reference/parseCommaSeparatedNewlineString.js new file mode 100644 index 0000000000..27df178f4d --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineString.js @@ -0,0 +1,7 @@ +//// [parseCommaSeparatedNewlineString.ts] +(a, +'') + +//// [parseCommaSeparatedNewlineString.js] +(a, + ''); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineString.symbols b/tests/baselines/reference/parseCommaSeparatedNewlineString.symbols similarity index 53% rename from tests/baselines/reference/parseCommaSeperatedNewlineString.symbols rename to tests/baselines/reference/parseCommaSeparatedNewlineString.symbols index 32e753e7f7..c5e111f98e 100644 --- a/tests/baselines/reference/parseCommaSeperatedNewlineString.symbols +++ b/tests/baselines/reference/parseCommaSeparatedNewlineString.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineString.ts === +=== tests/cases/compiler/parseCommaSeparatedNewlineString.ts === (a, No type information for this code.'') No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/parseCommaSeparatedNewlineString.types b/tests/baselines/reference/parseCommaSeparatedNewlineString.types new file mode 100644 index 0000000000..5e6c1e4bcc --- /dev/null +++ b/tests/baselines/reference/parseCommaSeparatedNewlineString.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/parseCommaSeparatedNewlineString.ts === +(a, +>(a,'') : "" +>a,'' : "" +>a : any + +'') +>'' : "" + diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNew.js b/tests/baselines/reference/parseCommaSeperatedNewlineNew.js deleted file mode 100644 index c1326c4780..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNew.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parseCommaSeperatedNewlineNew.ts] -(a, -new) - -//// [parseCommaSeperatedNewlineNew.js] -(a, - new ); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNew.types b/tests/baselines/reference/parseCommaSeperatedNewlineNew.types deleted file mode 100644 index a3c1cb2d64..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNew.types +++ /dev/null @@ -1,10 +0,0 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineNew.ts === -(a, ->(a,new) : any ->a,new : any ->a : any - -new) ->new : any -> : any - diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.js b/tests/baselines/reference/parseCommaSeperatedNewlineNumber.js deleted file mode 100644 index 167e604665..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parseCommaSeperatedNewlineNumber.ts] -(a, -1) - -//// [parseCommaSeperatedNewlineNumber.js] -(a, - 1); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.types b/tests/baselines/reference/parseCommaSeperatedNewlineNumber.types deleted file mode 100644 index 2b80be0b66..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineNumber.types +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts === -(a, ->(a,1) : 1 ->a,1 : 1 ->a : any - -1) ->1 : 1 - diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineString.js b/tests/baselines/reference/parseCommaSeperatedNewlineString.js deleted file mode 100644 index f7f96541c7..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineString.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parseCommaSeperatedNewlineString.ts] -(a, -'') - -//// [parseCommaSeperatedNewlineString.js] -(a, - ''); diff --git a/tests/baselines/reference/parseCommaSeperatedNewlineString.types b/tests/baselines/reference/parseCommaSeperatedNewlineString.types deleted file mode 100644 index 4c4030f56e..0000000000 --- a/tests/baselines/reference/parseCommaSeperatedNewlineString.types +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/parseCommaSeperatedNewlineString.ts === -(a, ->(a,'') : "" ->a,'' : "" ->a : any - -'') ->'' : "" - diff --git a/tests/cases/compiler/parseCommaSeperatedNewlineNew.ts b/tests/cases/compiler/parseCommaSeparatedNewlineNew.ts similarity index 100% rename from tests/cases/compiler/parseCommaSeperatedNewlineNew.ts rename to tests/cases/compiler/parseCommaSeparatedNewlineNew.ts diff --git a/tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts b/tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts similarity index 100% rename from tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts rename to tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts diff --git a/tests/cases/compiler/parseCommaSeperatedNewlineString.ts b/tests/cases/compiler/parseCommaSeparatedNewlineString.ts similarity index 100% rename from tests/cases/compiler/parseCommaSeperatedNewlineString.ts rename to tests/cases/compiler/parseCommaSeparatedNewlineString.ts diff --git a/tests/cases/conformance/enums/enumConstantMembers.ts b/tests/cases/conformance/enums/enumConstantMembers.ts index e56828db06..4970879b9c 100644 --- a/tests/cases/conformance/enums/enumConstantMembers.ts +++ b/tests/cases/conformance/enums/enumConstantMembers.ts @@ -16,4 +16,24 @@ declare enum E4 { a = 1, b = -1, c = 0.1 // Not a constant -} \ No newline at end of file +} + +enum E5 { + a = 1 / 0, + b = 2 / 0.0, + c = 1.0 / 0.0, + d = 0.0 / 0.0, + e = NaN, + f = Infinity, + g = -Infinity +} + +const enum E6 { + a = 1 / 0, + b = 2 / 0.0, + c = 1.0 / 0.0, + d = 0.0 / 0.0, + e = NaN, + f = Infinity, + g = -Infinity +} diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType1.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType1.ts new file mode 100644 index 0000000000..f00702e7bd --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType1.ts @@ -0,0 +1,17 @@ +/// + +//// type K = "foo" | "bar"; +//// interface SomeType { +//// a: string; +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +type SomeType = { + [prop in K]: any; +} & { + a: string; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType10.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType10.ts new file mode 100644 index 0000000000..073b20d916 --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType10.ts @@ -0,0 +1,23 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { bar: T; } +//// interface SomeType extends Foo, Bar { +//// a: number; +//// b: T; +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +interface Bar { bar: T; } +type SomeType = Foo & Bar & { + [prop in K]: any; +} & { + a: number; + b: T; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType11.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType11.ts new file mode 100644 index 0000000000..b82ee1ac17 --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType11.ts @@ -0,0 +1,23 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { bar: T; } +//// interface SomeType extends Foo, Bar { +//// a: number; +//// b: T; +//// readonly [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +interface Bar { bar: T; } +type SomeType = Foo & Bar & { + readonly [prop in K]: any; +} & { + a: number; + b: T; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType12.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType12.ts new file mode 100644 index 0000000000..6374dc43da --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType12.ts @@ -0,0 +1,12 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { bar: T; } +//// interface SomeType extends Foo, Bar { +//// a: number; +//// b: T; +//// readonly [prop: K]?: any; +//// } + +verify.not.codeFixAvailable() diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType2.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType2.ts new file mode 100644 index 0000000000..27dfc7cab0 --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType2.ts @@ -0,0 +1,17 @@ +/// + +//// type K = "foo" | "bar"; +//// type SomeType = { +//// a: string; +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +type SomeType = { + [prop in K]: any; +} & { + a: string; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType3.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType3.ts new file mode 100644 index 0000000000..b916eaca9b --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType3.ts @@ -0,0 +1,14 @@ +/// + +//// type K = "foo" | "bar"; +//// type SomeType = { +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +type SomeType = { + [prop in K]: any; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType4.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType4.ts new file mode 100644 index 0000000000..4077a7c04a --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType4.ts @@ -0,0 +1,14 @@ +/// + +//// type K = "foo" | "bar"; +//// interface SomeType { +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +type SomeType = { + [prop in K]: any; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType5.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType5.ts new file mode 100644 index 0000000000..869974f9ad --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType5.ts @@ -0,0 +1,8 @@ +/// + +//// type K = "foo" | "bar"; +//// class SomeType { +//// [prop: K]: any; +//// } + +verify.not.codeFixAvailable() diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType6.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType6.ts new file mode 100644 index 0000000000..b00f356b48 --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType6.ts @@ -0,0 +1,16 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface SomeType extends Foo { +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +type SomeType = Foo & { + [prop in K]: any; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType7.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType7.ts new file mode 100644 index 0000000000..a0a1e4eecc --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType7.ts @@ -0,0 +1,18 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { } +//// interface SomeType extends Foo, Bar { +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +interface Bar { } +type SomeType = Foo & Bar & { + [prop in K]: any; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType8.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType8.ts new file mode 100644 index 0000000000..6ee6c9f0aa --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType8.ts @@ -0,0 +1,21 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { } +//// interface SomeType extends Foo, Bar { +//// a: number; +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +interface Bar { } +type SomeType = Foo & Bar & { + [prop in K]: any; +} & { + a: number; +};` +}) diff --git a/tests/cases/fourslash/codeFixConvertToMappedObjectType9.ts b/tests/cases/fourslash/codeFixConvertToMappedObjectType9.ts new file mode 100644 index 0000000000..095296481f --- /dev/null +++ b/tests/cases/fourslash/codeFixConvertToMappedObjectType9.ts @@ -0,0 +1,21 @@ +/// + +//// type K = "foo" | "bar"; +//// interface Foo { } +//// interface Bar { bar: T; } +//// interface SomeType extends Foo, Bar { +//// a: number; +//// [prop: K]: any; +//// } + +verify.codeFix({ + description: `Convert 'SomeType' to mapped object type`, + newFileContent: `type K = "foo" | "bar"; +interface Foo { } +interface Bar { bar: T; } +type SomeType = Foo & Bar & { + [prop in K]: any; +} & { + a: number; +};` +}) diff --git a/tests/cases/fourslash/findAllReferencesOfJsonModule.ts b/tests/cases/fourslash/findAllReferencesOfJsonModule.ts new file mode 100644 index 0000000000..36f700b09e --- /dev/null +++ b/tests/cases/fourslash/findAllReferencesOfJsonModule.ts @@ -0,0 +1,14 @@ +/// + +// @resolveJsonModule: true +// @module: commonjs +// @esModuleInterop: true + +// @Filename: /foo.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}settings|] from "./settings.json"; +////[|settings|]; + +// @Filename: /settings.json +//// {} + +verify.singleReferenceGroup("import settings"); diff --git a/tests/cases/fourslash/getEditsForFileRename.ts b/tests/cases/fourslash/getEditsForFileRename.ts index f2694818d1..8e53883b37 100644 --- a/tests/cases/fourslash/getEditsForFileRename.ts +++ b/tests/cases/fourslash/getEditsForFileRename.ts @@ -1,5 +1,7 @@ /// +// See also `getEditsForFileRename_oldFileStillPresent.ts` + // @Filename: /a.ts /////// ////import old from "./src/old"; diff --git a/tests/cases/fourslash/getEditsForFileRename_oldFileStillPresent.ts b/tests/cases/fourslash/getEditsForFileRename_oldFileStillPresent.ts new file mode 100644 index 0000000000..c4ebf341a5 --- /dev/null +++ b/tests/cases/fourslash/getEditsForFileRename_oldFileStillPresent.ts @@ -0,0 +1,32 @@ +/// + +// Same test as `getEditsForFileRename.ts`, but with the old file not yet renamed. + +// @Filename: /src/old.ts +////stuff + +// @Filename: /a.ts +/////// +////import old from "./src/old"; + +// @Filename: /src/a.ts +/////// +////import old from "./old"; + +// @Filename: /src/foo/a.ts +/////// +////import old from "../old"; + +// @Filename: /tsconfig.json +////{ "files": ["/a.ts", "/src/a.ts", "/src/foo/a.ts", "/src/old.ts"] } + +verify.getEditsForFileRename({ + oldPath: "/src/old.ts", + newPath: "/src/new.ts", + newFileContents: { + "/a.ts": '/// \nimport old from "./src/new";', + "/src/a.ts": '/// \nimport old from "./new";', + "/src/foo/a.ts": '/// \nimport old from "../new";', + "/tsconfig.json": '{ "files": ["/a.ts", "/src/a.ts", "/src/foo/a.ts", "/src/new.ts"] }', + }, +}); diff --git a/tests/cases/fourslash/signatureHelpTypeArguments.ts b/tests/cases/fourslash/signatureHelpTypeArguments.ts new file mode 100644 index 0000000000..d08e9fc5ec --- /dev/null +++ b/tests/cases/fourslash/signatureHelpTypeArguments.ts @@ -0,0 +1,62 @@ +/// + +////declare function f(a: number, b: string, c: boolean): void; // ignored, not generic +////declare function f(): void; +////declare function f(): void; +////declare function f(): void; +////f(): void; +//// new(): void; +//// new(): void; +////}; +////new C(): void", + parameterName: "T", + parameterSpan: "T extends number", + }, + { + marker: "f1", + overloadsCount: 2, + text: "f(): void", + parameterName: "U", + parameterSpan: "U", + }, + { + marker: "f2", + text: "f(): void", + parameterName: "V", + parameterSpan: "V extends string", + }, + + { + marker: "C0", + overloadsCount: 3, + text: "C(): void", + parameterName: "T", + parameterSpan: "T extends number", + }, + { + marker: "C1", + overloadsCount: 2, + text: "C(): void", + parameterName: "U", + parameterSpan: "U", + }, + { + marker: "C2", + text: "C(): void", + parameterName: "V", + parameterSpan: "V extends string", + }, +);