From 1d93b76b3f0fecc726b5f64defbe8cb54400b959 Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Fri, 12 Jul 2019 14:04:19 +0300 Subject: [PATCH 1/6] Added "readonly" to Type Keywords --- src/harness/fourslash.ts | 6 +++--- src/services/utilities.ts | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ffc0759e92e..c8c1643b0e0 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -865,7 +865,7 @@ namespace FourSlash { ts.zipWith(actual, expected, (completion, expectedCompletion, index) => { const name = typeof expectedCompletion === "string" ? expectedCompletion : expectedCompletion.name; if (completion.name !== name) { - this.raiseError(`${marker ? JSON.stringify(marker) : "" } Expected completion at index ${index} to be ${name}, got ${completion.name}`); + this.raiseError(`${marker ? JSON.stringify(marker) : ""} Expected completion at index ${index} to be ${name}, got ${completion.name}`); } this.verifyCompletionEntry(completion, expectedCompletion); }); @@ -3742,7 +3742,7 @@ namespace FourSlashInterface { } export class Plugins { - constructor (private state: FourSlash.TestState) { + constructor(private state: FourSlash.TestState) { } public configurePlugin(pluginName: string, configuration: any): void { @@ -4565,7 +4565,7 @@ namespace FourSlashInterface { export const keywords: ReadonlyArray = keywordsWithUndefined.filter(k => k.name !== "undefined"); export const typeKeywords: ReadonlyArray = - ["false", "null", "true", "void", "any", "boolean", "keyof", "never", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry); + ["false", "null", "true", "void", "any", "boolean", "keyof", "never", "readonly", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry); const globalTypeDecls: ReadonlyArray = [ interfaceEntry("Symbol"), diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 44125fea6d0..7a273b64ad1 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1224,6 +1224,7 @@ namespace ts { SyntaxKind.NullKeyword, SyntaxKind.NumberKeyword, SyntaxKind.ObjectKeyword, + SyntaxKind.ReadonlyKeyword, SyntaxKind.StringKeyword, SyntaxKind.SymbolKeyword, SyntaxKind.TrueKeyword, @@ -1751,8 +1752,8 @@ namespace ts { function getSynthesizedDeepCloneWorker(node: T, renameMap?: Map, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T { const visited = (renameMap || checker || callback) ? - visitEachChild(node, wrapper, nullTransformationContext) : - visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext); + visitEachChild(node, wrapper, nullTransformationContext) : + visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext); if (visited === node) { // This only happens for leaf nodes - internal nodes always see their children change. From 74805c2e2392707af8aa606f8f7a52dfc28bdabb Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Fri, 12 Jul 2019 14:11:23 +0300 Subject: [PATCH 2/6] Fixed failing test due to changed details --- .../fourslash/documentHighlightsInvalidModifierLocations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/documentHighlightsInvalidModifierLocations.ts b/tests/cases/fourslash/documentHighlightsInvalidModifierLocations.ts index f008e632464..baa203901fd 100644 --- a/tests/cases/fourslash/documentHighlightsInvalidModifierLocations.ts +++ b/tests/cases/fourslash/documentHighlightsInvalidModifierLocations.ts @@ -6,5 +6,5 @@ ////function f([|readonly|] p) {} for (const r of test.ranges()) { - verify.documentHighlightsOf(r, [r]); + verify.documentHighlightsOf(r, test.ranges()); } From b2c555a57dfc2f2ad3c029d97ebc6f0932a2614e Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Fri, 12 Jul 2019 15:25:00 +0300 Subject: [PATCH 3/6] Added new keword compeltion filter for assertions --- src/services/completions.ts | 27 +++++++++++++------ .../cases/fourslash/completionListAsConst.ts | 11 ++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/completionListAsConst.ts diff --git a/src/services/completions.ts b/src/services/completions.ts index 6d1d48b22b8..f95526121a3 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -38,6 +38,7 @@ namespace ts.Completions { InterfaceElementKeywords, // Keywords inside interface body ConstructorParameterKeywords, // Keywords at constructor parameter FunctionLikeBodyKeywords, // Keywords at function like body + TypeAssertionKeywords, TypeKeywords, Last = TypeKeywords } @@ -441,7 +442,7 @@ namespace ts.Completions { (symbol.escapedName === InternalSymbolName.ExportEquals)) // Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase. ? firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined) - || codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target) + || codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target) : symbol.name; } @@ -632,9 +633,9 @@ namespace ts.Completions { // At `,`, treat this as the next argument after the comma. ? checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0)) : isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) && isEqualityOperatorKind(parent.operatorToken.kind) - // completion at `x ===/**/` should be for the right side - ? checker.getTypeAtLocation(parent.left) - : checker.getContextualType(previousToken as Expression); + // completion at `x ===/**/` should be for the right side + ? checker.getTypeAtLocation(parent.left) + : checker.getContextualType(previousToken as Expression); } } @@ -1181,7 +1182,11 @@ namespace ts.Completions { function filterGlobalCompletion(symbols: Symbol[]): void { const isTypeOnly = isTypeOnlyCompletion(); const allowTypes = isTypeOnly || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker); - if (isTypeOnly) keywordFilters = KeywordCompletionFilters.TypeKeywords; + if (isTypeOnly) { + keywordFilters = isInsideTypeAssertion() + ? KeywordCompletionFilters.TypeAssertionKeywords + : KeywordCompletionFilters.TypeKeywords; + } filterMutate(symbols, symbol => { if (!isSourceFile(location)) { @@ -1211,6 +1216,10 @@ namespace ts.Completions { }); } + function isInsideTypeAssertion(): boolean { + return isAsExpression(contextToken.parent); + } + function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && (isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)); } @@ -1434,7 +1443,7 @@ namespace ts.Completions { // 3. at the end of a regular expression (due to trailing flags like '/foo/g'). return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && ( rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) || - position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken))); + position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken))); } /** @@ -1944,8 +1953,8 @@ namespace ts.Completions { return baseSymbols.filter(propertySymbol => !existingMemberNames.has(propertySymbol.escapedName) && - !!propertySymbol.declarations && - !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private)); + !!propertySymbol.declarations && + !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private)); } /** @@ -2057,6 +2066,8 @@ namespace ts.Completions { return isParameterPropertyModifier(kind); case KeywordCompletionFilters.FunctionLikeBodyKeywords: return isFunctionLikeBodyKeyword(kind); + case KeywordCompletionFilters.TypeAssertionKeywords: + return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword; case KeywordCompletionFilters.TypeKeywords: return isTypeKeyword(kind); default: diff --git a/tests/cases/fourslash/completionListAsConst.ts b/tests/cases/fourslash/completionListAsConst.ts new file mode 100644 index 00000000000..3a8b706cea2 --- /dev/null +++ b/tests/cases/fourslash/completionListAsConst.ts @@ -0,0 +1,11 @@ +/// + +////const a = { +//// b: 42 as con/*0*/ +////}; +//// +////1 as con/*1*/ +//// +////const b = 42 as /*2*/ + +verify.completions({ marker: test.markers(), includes: [{ name: "const", sortText: completion.SortText.GlobalsOrKeywords }] }); From 9a37ef86676263a37f6068d02af96461aa00238a Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Tue, 16 Jul 2019 10:04:14 +0300 Subject: [PATCH 4/6] typeAssertionKeywords tests --- src/harness/fourslash.ts | 3 +++ tests/cases/fourslash/completionListAsConst.ts | 11 ----------- .../fourslash/completionsTypeAssertionKeywords.ts | 13 +++++++++++++ tests/cases/fourslash/fourslash.ts | 1 + 4 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 tests/cases/fourslash/completionListAsConst.ts create mode 100644 tests/cases/fourslash/completionsTypeAssertionKeywords.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index c8c1643b0e0..28e2659418f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -4681,6 +4681,9 @@ namespace FourSlashInterface { ]; } + export const typeAssertionKeywords: ReadonlyArray = + globalTypesPlus([keywordEntry("const")]); + function getInJsKeywords(keywords: ReadonlyArray): ReadonlyArray { return keywords.filter(keyword => { switch (keyword.name) { diff --git a/tests/cases/fourslash/completionListAsConst.ts b/tests/cases/fourslash/completionListAsConst.ts deleted file mode 100644 index 3a8b706cea2..00000000000 --- a/tests/cases/fourslash/completionListAsConst.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -////const a = { -//// b: 42 as con/*0*/ -////}; -//// -////1 as con/*1*/ -//// -////const b = 42 as /*2*/ - -verify.completions({ marker: test.markers(), includes: [{ name: "const", sortText: completion.SortText.GlobalsOrKeywords }] }); diff --git a/tests/cases/fourslash/completionsTypeAssertionKeywords.ts b/tests/cases/fourslash/completionsTypeAssertionKeywords.ts new file mode 100644 index 00000000000..100ab6e51e2 --- /dev/null +++ b/tests/cases/fourslash/completionsTypeAssertionKeywords.ts @@ -0,0 +1,13 @@ +/// + +////const a = { +//// b: 42 as /*0*/ +////}; +//// +////1 as /*1*/ +//// +////const b = 42 as /*2*/ +//// +////var c = 42 + +verify.completions({ marker: test.markers(), exact: completion.typeAssertionKeywords }); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 05799a15642..47c835d9c88 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -696,6 +696,7 @@ declare namespace completion { export const typeKeywords: ReadonlyArray; export const globalTypes: ReadonlyArray; export function globalTypesPlus(plus: ReadonlyArray): ReadonlyArray; + export const typeAssertionKeywords: ReadonlyArray; export const classElementKeywords: ReadonlyArray; export const classElementInJsKeywords: ReadonlyArray; export const constructorParameterKeywords: ReadonlyArray; From 0075b0a6a55ac6f27a05bdbfbcce4614f40761d1 Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Tue, 16 Jul 2019 10:06:16 +0300 Subject: [PATCH 5/6] Fix for angle-bracket type assertion --- src/services/completions.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index f95526121a3..cd70f0ddcdd 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1183,7 +1183,7 @@ namespace ts.Completions { const isTypeOnly = isTypeOnlyCompletion(); const allowTypes = isTypeOnly || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker); if (isTypeOnly) { - keywordFilters = isInsideTypeAssertion() + keywordFilters = isTypeAssertion() ? KeywordCompletionFilters.TypeAssertionKeywords : KeywordCompletionFilters.TypeKeywords; } @@ -1216,8 +1216,8 @@ namespace ts.Completions { }); } - function isInsideTypeAssertion(): boolean { - return isAsExpression(contextToken.parent); + function isTypeAssertion(): boolean { + return isAssertionExpression(contextToken.parent); } function isTypeOnlyCompletion(): boolean { @@ -1249,6 +1249,9 @@ namespace ts.Completions { case SyntaxKind.ExtendsKeyword: return parentKind === SyntaxKind.TypeParameter; + + case SyntaxKind.LessThanToken: + return parentKind === SyntaxKind.TypeAssertionExpression; } } return false; From 84cdc63d1faf89885cd2b24de57e2c29d8901651 Mon Sep 17 00:00:00 2001 From: Dmitrijs Minajevs Date: Tue, 16 Jul 2019 11:00:45 +0300 Subject: [PATCH 6/6] Merge angle-bracket fix --- src/services/completions.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index dc23c0a9b12..d7b40d14587 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1249,13 +1249,11 @@ namespace ts.Completions { return parentKind === SyntaxKind.AsExpression; case SyntaxKind.LessThanToken: - return parentKind === SyntaxKind.TypeReference; + return parentKind === SyntaxKind.TypeReference || + parentKind === SyntaxKind.TypeAssertionExpression; case SyntaxKind.ExtendsKeyword: return parentKind === SyntaxKind.TypeParameter; - - case SyntaxKind.LessThanToken: - return parentKind === SyntaxKind.TypeAssertionExpression; } } return false;