Merge branch 'master' into add-braces

This commit is contained in:
王文璐 2018-05-24 18:03:02 +08:00
commit d470f32d8a
62 changed files with 967 additions and 167 deletions

View file

@ -24752,7 +24752,11 @@ namespace ts {
case SyntaxKind.ParenthesizedExpression:
return evaluate((<ParenthesizedExpression>expr).expression);
case SyntaxKind.Identifier:
return nodeIsMissing(expr) ? 0 : evaluateEnumMember(expr, getSymbolOfNode(member.parent), (<Identifier>expr).escapedText);
const identifier = <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 = <PropertyAccessExpression | ElementAccessExpression>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

View file

@ -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$))?)*",

View file

@ -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
}
}

View file

@ -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) {

View file

@ -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",

View file

@ -1008,6 +1008,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_missing_typeof_95052" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add missing 'typeof']]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[新增遺漏的 'typeof']]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_qualifier_to_all_unresolved_variables_matching_a_member_name_95037" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add qualifier to all unresolved variables matching a member name]]></Val>
@ -1125,6 +1134,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";All_variables_are_unused_6199" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[All variables are unused.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[所有變數都未使用。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typech_6011" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Allow default imports from modules with no default export. This does not affect code emit, just typechecking.]]></Val>
@ -6564,6 +6582,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_all_unused_labels_95054" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove all unused labels]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[移除所有未使用的標籤]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_declaration_for_Colon_0_90004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove declaration for: '{0}']]></Val>
@ -6603,6 +6630,24 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_unused_label_95053" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove unused label]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[移除未使用的標籤]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_variable_statement_90010" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove variable statement]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[移除變數陳述式]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_import_with_0_95015" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace import with '{0}'.]]></Val>

View file

@ -1019,10 +1019,13 @@
</Item>
<Item ItemId=";Add_missing_typeof_95052" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add missing typeof]]></Val>
<Val><![CDATA[Add missing 'typeof']]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Ajouter un typeof manquant]]></Val>
<Val><![CDATA[Ajouter un 'typeof' manquant]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Add missing typeof]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>
@ -1143,6 +1146,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";All_variables_are_unused_6199" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[All variables are unused.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Toutes les variables sont inutilisées.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typech_6011" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Allow default imports from modules with no default export. This does not affect code emit, just typechecking.]]></Val>
@ -6582,6 +6594,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_all_unused_labels_95054" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove all unused labels]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Supprimer toutes les étiquettes inutilisées]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_declaration_for_Colon_0_90004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove declaration for: '{0}']]></Val>
@ -6621,6 +6642,24 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_unused_label_95053" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove unused label]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Supprimer l'étiquette inutilisée]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_variable_statement_90010" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove variable statement]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Supprimer l'instruction de variable]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_import_with_0_95015" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace import with '{0}'.]]></Val>

View file

@ -1007,6 +1007,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_missing_typeof_95052" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add missing 'typeof']]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Добавить отсутствующий "typeof"]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_qualifier_to_all_unresolved_variables_matching_a_member_name_95037" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add qualifier to all unresolved variables matching a member name]]></Val>
@ -1124,6 +1133,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";All_variables_are_unused_6199" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[All variables are unused.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Ни одна переменная не используется.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typech_6011" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Allow default imports from modules with no default export. This does not affect code emit, just typechecking.]]></Val>
@ -6563,6 +6581,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_all_unused_labels_95054" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove all unused labels]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Удалить все неиспользуемые метки]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_declaration_for_Colon_0_90004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove declaration for: '{0}']]></Val>
@ -6602,6 +6629,24 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_unused_label_95053" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove unused label]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Удалить неиспользуемую метку]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_variable_statement_90010" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove variable statement]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Удалить оператор с переменной]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_import_with_0_95015" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace import with '{0}'.]]></Val>

View file

@ -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",

View file

@ -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",

View file

@ -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 : (<TypeLiteralNode>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));
}
}

View file

@ -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);
}

View file

@ -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<true>();
@ -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)

View file

@ -32,23 +32,20 @@ namespace ts {
}
function getImportsToUpdate(program: Program, oldFilePath: string, host: LanguageServiceHost): ReadonlyArray<ToUpdate> {
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 });
}
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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);

View file

@ -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<Signature>, 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(<LiteralExpression>node, position)) {
return getArgumentListInfoForTemplate(<TaggedTemplateExpression>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 = <TemplateExpression>node.parent;
else if (isTemplateHead(node) && parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateExpression = <TemplateExpression>parent;
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
const argumentIndex = isInsideTemplateLiteral(<LiteralExpression>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 = <TemplateSpan>node.parent;
const templateExpression = templateSpan.parent;
const tagExpression = <TaggedTemplateExpression>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(<LiteralExpression>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 { ... }
// <MainButton /*signatureHelp*/
const attributeSpanStart = node.parent.attributes.getFullStart();
const attributeSpanEnd = skipTrivia(sourceFile.text, node.parent.attributes.getEnd(), /*stopAfterLineBreak*/ false);
const attributeSpanStart = parent.attributes.pos;
const attributeSpanEnd = skipTrivia(sourceFile.text, parent.attributes.end, /*stopAfterLineBreak*/ false);
return {
kind: ArgumentListKind.JSXAttributesArguments,
invocation: node.parent,
invocation: { kind: InvocationKind.Call, node: parent },
argumentsSpan: createTextSpan(attributeSpanStart, attributeSpanEnd - attributeSpanStart),
argumentIndex: 0,
argumentCount: 1
};
}
else {
const typeArgInfo = isPossiblyTypeArgumentPosition(node, sourceFile);
if (typeArgInfo) {
const { called, nTypeArguments } = typeArgInfo;
const invocation: Invocation = { kind: InvocationKind.TypeArgs, called };
const argumentsSpan = createTextSpanFromBounds(called.getStart(sourceFile), node.end);
return { kind: ArgumentListKind.TypeArguments, invocation, argumentsSpan, argumentIndex: nTypeArguments, argumentCount: nTypeArguments + 1 };
}
}
return undefined;
}
@ -269,7 +298,7 @@ namespace ts.SignatureHelp {
}
return {
kind: ArgumentListKind.TaggedTemplateArguments,
invocation: tagExpression,
invocation: { kind: InvocationKind.Call, node: tagExpression },
argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression, sourceFile),
argumentIndex,
argumentCount
@ -313,25 +342,15 @@ namespace ts.SignatureHelp {
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
export function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined {
for (let n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) {
if (isFunctionBlock(n)) {
return undefined;
}
function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined {
for (let n = node; !isBlock(n) && !isSourceFile(n); n = n.parent) {
// If the node is not a subspan of its parent, this is a big problem.
// There have been crashes that might be caused by this violation.
if (n.pos < n.parent.pos || n.end > 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<Signature>, 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<SignatureHelpItem>(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 {

View file

@ -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",

View file

@ -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());
}

View file

@ -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.
}

View file

@ -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 = {}));

View file

@ -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, --, --))
}

View file

@ -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
}

View file

@ -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'.

View file

@ -0,0 +1,7 @@
//// [parseCommaSeparatedNewlineNew.ts]
(a,
new)
//// [parseCommaSeparatedNewlineNew.js]
(a,
new );

View file

@ -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.

View file

@ -0,0 +1,10 @@
=== tests/cases/compiler/parseCommaSeparatedNewlineNew.ts ===
(a,
>(a,new) : any
>a,new : any
>a : any
new)
>new : any
> : any

View file

@ -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'.

View file

@ -0,0 +1,7 @@
//// [parseCommaSeparatedNewlineNumber.ts]
(a,
1)
//// [parseCommaSeparatedNewlineNumber.js]
(a,
1);

View file

@ -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.

View file

@ -0,0 +1,9 @@
=== tests/cases/compiler/parseCommaSeparatedNewlineNumber.ts ===
(a,
>(a,1) : 1
>a,1 : 1
>a : any
1)
>1 : 1

View file

@ -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'.

View file

@ -0,0 +1,7 @@
//// [parseCommaSeparatedNewlineString.ts]
(a,
'')
//// [parseCommaSeparatedNewlineString.js]
(a,
'');

View file

@ -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.

View file

@ -0,0 +1,9 @@
=== tests/cases/compiler/parseCommaSeparatedNewlineString.ts ===
(a,
>(a,'') : ""
>a,'' : ""
>a : any
'')
>'' : ""

View file

@ -1,7 +0,0 @@
//// [parseCommaSeperatedNewlineNew.ts]
(a,
new)
//// [parseCommaSeperatedNewlineNew.js]
(a,
new );

View file

@ -1,10 +0,0 @@
=== tests/cases/compiler/parseCommaSeperatedNewlineNew.ts ===
(a,
>(a,new) : any
>a,new : any
>a : any
new)
>new : any
> : any

View file

@ -1,7 +0,0 @@
//// [parseCommaSeperatedNewlineNumber.ts]
(a,
1)
//// [parseCommaSeperatedNewlineNumber.js]
(a,
1);

View file

@ -1,9 +0,0 @@
=== tests/cases/compiler/parseCommaSeperatedNewlineNumber.ts ===
(a,
>(a,1) : 1
>a,1 : 1
>a : any
1)
>1 : 1

View file

@ -1,7 +0,0 @@
//// [parseCommaSeperatedNewlineString.ts]
(a,
'')
//// [parseCommaSeperatedNewlineString.js]
(a,
'');

View file

@ -1,9 +0,0 @@
=== tests/cases/compiler/parseCommaSeperatedNewlineString.ts ===
(a,
>(a,'') : ""
>a,'' : ""
>a : any
'')
>'' : ""

View file

@ -16,4 +16,24 @@ 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
}

View file

@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,23 @@
/// <reference path='fourslash.ts' />
//// type K = "foo" | "bar";
//// interface Foo { }
//// interface Bar<T> { bar: T; }
//// interface SomeType<T> extends Foo, Bar<T> {
//// 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<T> { bar: T; }
type SomeType<T> = Foo & Bar<T> & {
[prop in K]: any;
} & {
a: number;
b: T;
};`
})

View file

@ -0,0 +1,23 @@
/// <reference path='fourslash.ts' />
//// type K = "foo" | "bar";
//// interface Foo { }
//// interface Bar<T> { bar: T; }
//// interface SomeType<T> extends Foo, Bar<T> {
//// 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<T> { bar: T; }
type SomeType<T> = Foo & Bar<T> & {
readonly [prop in K]: any;
} & {
a: number;
b: T;
};`
})

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// type K = "foo" | "bar";
//// interface Foo { }
//// interface Bar<T> { bar: T; }
//// interface SomeType<T> extends Foo, Bar<T> {
//// a: number;
//// b: T;
//// readonly [prop: K]?: any;
//// }
verify.not.codeFixAvailable()

View file

@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
//// type K = "foo" | "bar";
//// class SomeType {
//// [prop: K]: any;
//// }
verify.not.codeFixAvailable()

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,21 @@
/// <reference path='fourslash.ts' />
//// 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;
};`
})

View file

@ -0,0 +1,21 @@
/// <reference path='fourslash.ts' />
//// type K = "foo" | "bar";
//// interface Foo { }
//// interface Bar<T> { bar: T; }
//// interface SomeType extends Foo, Bar<number> {
//// a: number;
//// [prop: K]: any;
//// }
verify.codeFix({
description: `Convert 'SomeType' to mapped object type`,
newFileContent: `type K = "foo" | "bar";
interface Foo { }
interface Bar<T> { bar: T; }
type SomeType = Foo & Bar<number> & {
[prop in K]: any;
} & {
a: number;
};`
})

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
// @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");

View file

@ -1,5 +1,7 @@
/// <reference path='fourslash.ts' />
// See also `getEditsForFileRename_oldFileStillPresent.ts`
// @Filename: /a.ts
/////// <reference path="./src/old.ts" />
////import old from "./src/old";

View file

@ -0,0 +1,32 @@
/// <reference path='fourslash.ts' />
// Same test as `getEditsForFileRename.ts`, but with the old file not yet renamed.
// @Filename: /src/old.ts
////stuff
// @Filename: /a.ts
/////// <reference path="./src/old.ts" />
////import old from "./src/old";
// @Filename: /src/a.ts
/////// <reference path="./old.ts" />
////import old from "./old";
// @Filename: /src/foo/a.ts
/////// <reference path="../old.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": '/// <reference path="./src/new.ts" />\nimport old from "./src/new";',
"/src/a.ts": '/// <reference path="./new.ts" />\nimport old from "./new";',
"/src/foo/a.ts": '/// <reference path="../new.ts" />\nimport old from "../new";',
"/tsconfig.json": '{ "files": ["/a.ts", "/src/a.ts", "/src/foo/a.ts", "/src/new.ts"] }',
},
});

View file

@ -0,0 +1,62 @@
/// <reference path="fourslash.ts"/>
////declare function f(a: number, b: string, c: boolean): void; // ignored, not generic
////declare function f<T extends number>(): void;
////declare function f<T, U>(): void;
////declare function f<T, U, V extends string>(): void;
////f</*f0*/;
////f<number, /*f1*/;
////f<number, string, /*f2*/;
////
////declare const C: {
//// new<T extends number>(): void;
//// new<T, U>(): void;
//// new<T, U, V extends string>(): void;
////};
////new C</*C0*/;
////new C<number, /*C1*/;
////new C<number, string, /*C2*/;
verify.signatureHelp(
{
marker: "f0",
overloadsCount: 3,
text: "f<T extends number>(): void",
parameterName: "T",
parameterSpan: "T extends number",
},
{
marker: "f1",
overloadsCount: 2,
text: "f<T, U>(): void",
parameterName: "U",
parameterSpan: "U",
},
{
marker: "f2",
text: "f<T, U, V extends string>(): void",
parameterName: "V",
parameterSpan: "V extends string",
},
{
marker: "C0",
overloadsCount: 3,
text: "C<T extends number>(): void",
parameterName: "T",
parameterSpan: "T extends number",
},
{
marker: "C1",
overloadsCount: 2,
text: "C<T, U>(): void",
parameterName: "U",
parameterSpan: "U",
},
{
marker: "C2",
text: "C<T, U, V extends string>(): void",
parameterName: "V",
parameterSpan: "V extends string",
},
);