diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 0101d67441..6c2bc73b0e 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -85,13 +85,20 @@ function parseFileContent(filename: string, content: string): GoTest | undefined }; for (const statement of statements) { const result = parseFourslashStatement(statement); + if (result === SKIP_STATEMENT) { + // Skip this statement but continue parsing + continue; + } if (!result) { + // Could not parse this statement - mark file as unparsed unparsedFiles.push(filename); return undefined; } - else { - goTest.commands.push(...result); - } + goTest.commands.push(...result); + } + // Skip tests that have no commands (e.g., only syntactic classifications) + if (goTest.commands.length === 0) { + return undefined; } return goTest; } @@ -134,11 +141,22 @@ function getTestInput(content: string): string { return `\`${testInput.join("\n")}\``; } +// Sentinel value to indicate a statement should be skipped but parsing should continue +const SKIP_STATEMENT: unique symbol = Symbol("SKIP_STATEMENT"); +type SkipStatement = typeof SKIP_STATEMENT; + /** * Parses a Strada fourslash statement and returns the corresponding Corsa commands. - * @returns an array of commands if the statement is a valid fourslash command, or `false` if the statement could not be parsed. + * @returns an array of commands if the statement is a valid fourslash command, + * SKIP_STATEMENT if the statement should be skipped but parsing should continue, + * or `undefined` if the statement could not be parsed and the file should be marked as unparsed. */ -function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { +function parseFourslashStatement(statement: ts.Statement): Cmd[] | SkipStatement | undefined { + // Skip empty statements (bare semicolons) + if (ts.isEmptyStatement(statement)) { + return SKIP_STATEMENT; + } + if (ts.isVariableStatement(statement)) { // variable declarations (for ranges and markers), e.g. `const range = test.ranges()[0];` return []; @@ -208,6 +226,10 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { case "renameInfoSucceeded": case "renameInfoFailed": return parseRenameInfo(func.text, callExpression.arguments); + case "semanticClassificationsAre": + return parseSemanticClassificationsAre(callExpression.arguments); + case "syntacticClassificationsAre": + return SKIP_STATEMENT; } } // `goTo....` @@ -1439,6 +1461,71 @@ function parseBaselineSmartSelection(args: ts.NodeArray): Cmd { }; } +function parseSemanticClassificationsAre(args: readonly ts.Expression[]): [VerifySemanticClassificationsCmd] | SkipStatement | undefined { + if (args.length < 1) { + console.error("semanticClassificationsAre requires at least a format argument"); + return undefined; + } + + const formatArg = args[0]; + if (!ts.isStringLiteralLike(formatArg)) { + console.error("semanticClassificationsAre first argument must be a string literal"); + return undefined; + } + + const format = formatArg.text; + + // Only handle "2020" format for semantic tokens + if (format !== "2020") { + // Skip other formats like "original" - return sentinel to continue parsing + return SKIP_STATEMENT; + } + + const tokens: Array<{ type: string; text: string; }> = []; + + // Parse the classification tokens (c2.semanticToken("type", "text")) + for (let i = 1; i < args.length; i++) { + const arg = args[i]; + if (!ts.isCallExpression(arg)) { + console.error(`Expected call expression for token at index ${i}`); + return undefined; + } + + if (!ts.isPropertyAccessExpression(arg.expression) || arg.expression.name.text !== "semanticToken") { + console.error(`Expected semanticToken call at index ${i}`); + return undefined; + } + + if (arg.arguments.length < 2) { + console.error(`semanticToken requires 2 arguments at index ${i}`); + return undefined; + } + + const typeArg = arg.arguments[0]; + const textArg = arg.arguments[1]; + + if (!ts.isStringLiteralLike(typeArg) || !ts.isStringLiteralLike(textArg)) { + console.error(`semanticToken arguments must be string literals at index ${i}`); + return undefined; + } + + // Map TypeScript's internal "member" type to LSP's "method" type + let tokenType = typeArg.text; + tokenType = tokenType.replace(/\bmember\b/g, "method"); + + tokens.push({ + type: tokenType, + text: textArg.text, + }); + } + + return [{ + kind: "verifySemanticClassifications", + format, + tokens, + }]; +} + function parseKind(expr: ts.Expression): string | undefined { if (!ts.isStringLiteral(expr)) { console.error(`Expected string literal for kind, got ${expr.getText()}`); @@ -1649,6 +1736,12 @@ interface VerifyRenameInfoCmd { preferences: string; } +interface VerifySemanticClassificationsCmd { + kind: "verifySemanticClassifications"; + format: string; + tokens: Array<{ type: string; text: string; }>; +} + type Cmd = | VerifyCompletionsCmd | VerifyApplyCodeActionFromCompletionCmd @@ -1662,7 +1755,8 @@ type Cmd = | EditCmd | VerifyQuickInfoCmd | VerifyBaselineRenameCmd - | VerifyRenameInfoCmd; + | VerifyRenameInfoCmd + | VerifySemanticClassificationsCmd; function generateVerifyCompletions({ marker, args, isNewIdentifierLocation, andApplyCodeActionArgs }: VerifyCompletionsCmd): string { let expectedList: string; @@ -1759,6 +1853,14 @@ function generateBaselineRename({ kind, args, preferences }: VerifyBaselineRenam } } +function generateSemanticClassifications({ format, tokens }: VerifySemanticClassificationsCmd): string { + const tokensStr = tokens.map(t => `{Type: ${getGoStringLiteral(t.type)}, Text: ${getGoStringLiteral(t.text)}}`).join(",\n\t\t"); + const maybeComma = tokens.length > 0 ? "," : ""; + return `f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + ${tokensStr}${maybeComma} + })`; +} + function generateCmd(cmd: Cmd): string { switch (cmd.kind) { case "verifyCompletions": @@ -1795,6 +1897,8 @@ function generateCmd(cmd: Cmd): string { return `f.VerifyRenameSucceeded(t, ${cmd.preferences})`; case "renameInfoFailed": return `f.VerifyRenameFailed(t, ${cmd.preferences})`; + case "verifySemanticClassifications": + return generateSemanticClassifications(cmd); default: let neverCommand: never = cmd; throw new Error(`Unknown command kind: ${neverCommand as Cmd["kind"]}`); diff --git a/internal/fourslash/_scripts/manualTests.txt b/internal/fourslash/_scripts/manualTests.txt index 492d95e520..dbe68104cd 100644 --- a/internal/fourslash/_scripts/manualTests.txt +++ b/internal/fourslash/_scripts/manualTests.txt @@ -4,4 +4,5 @@ completionsSelfDeclaring1 completionsWithDeprecatedTag4 renameDefaultKeyword renameForDefaultExport01 +semanticModernClassificationFunctions tsxCompletion12 diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 1b78246b62..32a91ecc75 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -50,6 +50,10 @@ type FourslashTest struct { lastKnownMarkerName *string activeFilename string selectionEnd *lsproto.Position + + // Semantic token configuration + semanticTokenTypes []string + semanticTokenModifiers []string } type scriptInfo struct { @@ -183,15 +187,17 @@ func NewFourslash(t *testing.T, capabilities *lsproto.ClientCapabilities, conten }) f := &FourslashTest{ - server: server, - in: inputWriter, - out: outputReader, - testData: &testData, - userPreferences: lsutil.NewDefaultUserPreferences(), // !!! parse default preferences for fourslash case? - vfs: fs, - scriptInfos: scriptInfos, - converters: converters, - baselines: make(map[string]*strings.Builder), + server: server, + in: inputWriter, + out: outputReader, + testData: &testData, + userPreferences: lsutil.NewDefaultUserPreferences(), // !!! parse default preferences for fourslash case? + vfs: fs, + scriptInfos: scriptInfos, + converters: converters, + baselines: make(map[string]*strings.Builder), + semanticTokenTypes: defaultSemanticTokenTypes(), + semanticTokenModifiers: defaultSemanticTokenModifiers(), } // !!! temporary; remove when we have `handleDidChangeConfiguration`/implicit project config support @@ -231,6 +237,50 @@ func (f *FourslashTest) initialize(t *testing.T, capabilities *lsproto.ClientCap sendNotification(t, f, lsproto.InitializedInfo, &lsproto.InitializedParams{}) } +func defaultSemanticTokenTypes() []string { + return []string{ + string(lsproto.SemanticTokenTypesnamespace), + string(lsproto.SemanticTokenTypesclass), + string(lsproto.SemanticTokenTypesenum), + string(lsproto.SemanticTokenTypesinterface), + string(lsproto.SemanticTokenTypesstruct), + string(lsproto.SemanticTokenTypestypeParameter), + string(lsproto.SemanticTokenTypestype), + string(lsproto.SemanticTokenTypesparameter), + string(lsproto.SemanticTokenTypesvariable), + string(lsproto.SemanticTokenTypesproperty), + string(lsproto.SemanticTokenTypesenumMember), + string(lsproto.SemanticTokenTypesdecorator), + string(lsproto.SemanticTokenTypesevent), + string(lsproto.SemanticTokenTypesfunction), + string(lsproto.SemanticTokenTypesmethod), + string(lsproto.SemanticTokenTypesmacro), + string(lsproto.SemanticTokenTypeslabel), + string(lsproto.SemanticTokenTypescomment), + string(lsproto.SemanticTokenTypesstring), + string(lsproto.SemanticTokenTypeskeyword), + string(lsproto.SemanticTokenTypesnumber), + string(lsproto.SemanticTokenTypesregexp), + string(lsproto.SemanticTokenTypesoperator), + } +} + +func defaultSemanticTokenModifiers() []string { + return []string{ + string(lsproto.SemanticTokenModifiersdeclaration), + string(lsproto.SemanticTokenModifiersdefinition), + string(lsproto.SemanticTokenModifiersreadonly), + string(lsproto.SemanticTokenModifiersstatic), + string(lsproto.SemanticTokenModifiersdeprecated), + string(lsproto.SemanticTokenModifiersabstract), + string(lsproto.SemanticTokenModifiersasync), + string(lsproto.SemanticTokenModifiersmodification), + string(lsproto.SemanticTokenModifiersdocumentation), + string(lsproto.SemanticTokenModifiersdefaultLibrary), + "local", + } +} + var ( ptrTrue = ptrTo(true) defaultCompletionCapabilities = &lsproto.CompletionClientCapabilities{ @@ -293,6 +343,18 @@ func getCapabilitiesWithDefaults(capabilities *lsproto.ClientCapabilities) *lspr }, } } + if capabilitiesWithDefaults.TextDocument.SemanticTokens == nil { + capabilitiesWithDefaults.TextDocument.SemanticTokens = &lsproto.SemanticTokensClientCapabilities{ + Requests: &lsproto.ClientSemanticTokensRequestOptions{ + Full: &lsproto.BooleanOrClientSemanticTokensRequestFullDelta{ + Boolean: ptrTrue, + }, + }, + TokenTypes: defaultSemanticTokenTypes(), + TokenModifiers: defaultSemanticTokenModifiers(), + Formats: []lsproto.TokenFormat{lsproto.TokenFormatRelative}, + } + } if capabilitiesWithDefaults.Workspace == nil { capabilitiesWithDefaults.Workspace = &lsproto.WorkspaceClientCapabilities{} } diff --git a/internal/fourslash/semantictokens.go b/internal/fourslash/semantictokens.go new file mode 100644 index 0000000000..e4ae30ac83 --- /dev/null +++ b/internal/fourslash/semantictokens.go @@ -0,0 +1,140 @@ +package fourslash + +import ( + "fmt" + "strings" + "testing" + + "github.com/microsoft/typescript-go/internal/ls/lsconv" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" +) + +type SemanticToken struct { + Type string + Text string +} + +func (f *FourslashTest) VerifySemanticTokens(t *testing.T, expected []SemanticToken) { + t.Helper() + + params := &lsproto.SemanticTokensParams{ + TextDocument: lsproto.TextDocumentIdentifier{ + Uri: lsconv.FileNameToDocumentURI(f.activeFilename), + }, + } + + resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentSemanticTokensFullInfo, params) + if resMsg == nil { + t.Fatal("Nil response received for semantic tokens request") + } + if !resultOk { + resp := resMsg.AsResponse() + if resp.Error != nil { + t.Fatalf("Semantic tokens request returned error: code=%d, message=%s", resp.Error.Code, resp.Error.Message) + } + t.Fatalf("Unexpected response type for semantic tokens request: %T", resp.Result) + } + + if result.SemanticTokens == nil { + if len(expected) == 0 { + return + } + t.Fatal("Expected semantic tokens but got nil") + } + + // Decode the semantic tokens using token types/modifiers from the test configuration + actual := decodeSemanticTokens(f, result.SemanticTokens.Data, f.semanticTokenTypes, f.semanticTokenModifiers) + + // Compare with expected + if len(actual) != len(expected) { + t.Fatalf("Expected %d semantic tokens, got %d\n\nExpected:\n%s\n\nActual:\n%s", + len(expected), len(actual), + formatSemanticTokens(expected), + formatSemanticTokens(actual)) + } + + for i, exp := range expected { + act := actual[i] + if exp.Type != act.Type || exp.Text != act.Text { + t.Errorf("Token %d mismatch:\n Expected: {Type: %q, Text: %q}\n Actual: {Type: %q, Text: %q}", + i, exp.Type, exp.Text, act.Type, act.Text) + } + } +} + +func decodeSemanticTokens(f *FourslashTest, data []uint32, tokenTypes, tokenModifiers []string) []SemanticToken { + if len(data)%5 != 0 { + panic(fmt.Sprintf("Invalid semantic tokens data length: %d", len(data))) + } + + scriptInfo := f.scriptInfos[f.activeFilename] + converters := lsconv.NewConverters(lsproto.PositionEncodingKindUTF8, func(_ string) *lsconv.LSPLineMap { + return scriptInfo.lineMap + }) + + var tokens []SemanticToken + prevLine := uint32(0) + prevChar := uint32(0) + + for i := 0; i < len(data); i += 5 { + deltaLine := data[i] + deltaChar := data[i+1] + length := data[i+2] + tokenTypeIdx := data[i+3] + tokenModifierMask := data[i+4] + + // Calculate absolute position + line := prevLine + deltaLine + var char uint32 + if deltaLine == 0 { + char = prevChar + deltaChar + } else { + char = deltaChar + } + + // Get token type + if int(tokenTypeIdx) >= len(tokenTypes) { + panic(fmt.Sprintf("Token type index out of range: %d", tokenTypeIdx)) + } + tokenType := tokenTypes[tokenTypeIdx] + + // Get modifiers + var modifiers []string + for i, mod := range tokenModifiers { + if tokenModifierMask&(1< 0 { + typeStr = typeStr + "." + strings.Join(modifiers, ".") + } + + // Get the text + startPos := lsproto.Position{Line: line, Character: char} + endPos := lsproto.Position{Line: line, Character: char + length} + startOffset := int(converters.LineAndCharacterToPosition(scriptInfo, startPos)) + endOffset := int(converters.LineAndCharacterToPosition(scriptInfo, endPos)) + text := scriptInfo.content[startOffset:endOffset] + + tokens = append(tokens, SemanticToken{ + Type: typeStr, + Text: text, + }) + + prevLine = line + prevChar = char + } + + return tokens +} + +func formatSemanticTokens(tokens []SemanticToken) string { + var lines []string + for i, tok := range tokens { + lines = append(lines, fmt.Sprintf(" [%d] {Type: %q, Text: %q}", i, tok.Type, tok.Text)) + } + return strings.Join(lines, "\n") +} diff --git a/internal/fourslash/tests/gen/incrementalJsDocAdjustsLengthsRight_test.go b/internal/fourslash/tests/gen/incrementalJsDocAdjustsLengthsRight_test.go new file mode 100644 index 0000000000..5075e6a3c8 --- /dev/null +++ b/internal/fourslash/tests/gen/incrementalJsDocAdjustsLengthsRight_test.go @@ -0,0 +1,24 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestIncrementalJsDocAdjustsLengthsRight(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true + +/** + * Pad ` + "`" + `str` + "`" + ` to ` + "`" + `width` + "`" + `. + * + * @param {String} str + * @param {Number} wid/*1*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.Insert(t, "th\n@") +} diff --git a/internal/fourslash/tests/gen/renameDefaultImport_test.go b/internal/fourslash/tests/gen/renameDefaultImport_test.go new file mode 100644 index 0000000000..e75a3fb9f5 --- /dev/null +++ b/internal/fourslash/tests/gen/renameDefaultImport_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestRenameDefaultImport(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: B.ts +[|export default class /*1*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}B|] { + test() { + } +}|] +// @Filename: A.ts +[|import /*2*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}B|] from "./B";|] +let b = new [|B|](); +b.test();` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyBaselineFindAllReferences(t, "1", "2") + f.VerifyBaselineRename(t, nil /*preferences*/, f.Ranges()[1], f.Ranges()[3], f.Ranges()[4]) + f.VerifyBaselineDocumentHighlights(t, nil /*preferences*/, "1") +} diff --git a/internal/fourslash/tests/gen/semanticClassification1_test.go b/internal/fourslash/tests/gen/semanticClassification1_test.go new file mode 100644 index 0000000000..2b2b086f2d --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassification1_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassification1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export interface /*1*/I { + } +} +interface /*2*/X extends /*3*/M./*4*/I { }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "interface.declaration", Text: "X"}, + {Type: "namespace", Text: "M"}, + {Type: "interface", Text: "I"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassification2_test.go b/internal/fourslash/tests/gen/semanticClassification2_test.go new file mode 100644 index 0000000000..ac2faf4e12 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassification2_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassification2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `interface /*0*/Thing { + toExponential(): number; +} + +var Thing = 0; +Thing.toExponential();` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "interface.declaration", Text: "Thing"}, + {Type: "method.declaration", Text: "toExponential"}, + {Type: "variable.declaration", Text: "Thing"}, + {Type: "variable", Text: "Thing"}, + {Type: "method.defaultLibrary", Text: "toExponential"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationAlias_test.go b/internal/fourslash/tests/gen/semanticClassificationAlias_test.go new file mode 100644 index 0000000000..ad89ca96f3 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationAlias_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationAlias(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export type x = number; +export class y {}; +// @Filename: /b.ts +import { /*0*/x, /*1*/y } from "./a"; +const v: /*2*/x = /*3*/y;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/b.ts") + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration.readonly", Text: "v"}, + {Type: "type", Text: "x"}, + {Type: "class", Text: "y"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationClassExpression_test.go b/internal/fourslash/tests/gen/semanticClassificationClassExpression_test.go new file mode 100644 index 0000000000..cfb534053e --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationClassExpression_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationClassExpression(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `var x = class /*0*/C {} +class /*1*/C {} +class /*2*/D extends class /*3*/B{} { }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "x"}, + {Type: "class", Text: "C"}, + {Type: "class.declaration", Text: "C"}, + {Type: "class.declaration", Text: "D"}, + {Type: "class", Text: "B"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationInTemplateExpressions_test.go b/internal/fourslash/tests/gen/semanticClassificationInTemplateExpressions_test.go new file mode 100644 index 0000000000..73158e28e4 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationInTemplateExpressions_test.go @@ -0,0 +1,37 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationInTemplateExpressions(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export class /*1*/C { + static x; + } + export enum /*2*/E { + E1 = 0 + } +} +` + "`" + `abcd${ /*3*/M./*4*/C.x + /*5*/M./*6*/E.E1}efg` + "`" + `` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "class.declaration", Text: "C"}, + {Type: "property.declaration.static", Text: "x"}, + {Type: "enum.declaration", Text: "E"}, + {Type: "enumMember.declaration.readonly", Text: "E1"}, + {Type: "namespace", Text: "M"}, + {Type: "class", Text: "C"}, + {Type: "property.static", Text: "x"}, + {Type: "namespace", Text: "M"}, + {Type: "enum", Text: "E"}, + {Type: "enumMember.readonly", Text: "E1"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName1_test.go b/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName1_test.go new file mode 100644 index 0000000000..c0e122f37c --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName1_test.go @@ -0,0 +1,42 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationInstantiatedModuleWithVariableOfSameName1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export interface /*1*/I { + } + var x = 10; +} + +var /*2*/M = { + foo: 10, + bar: 20 +} + +var v: /*3*/M./*4*/I; + +var x = /*5*/M;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "variable.declaration.local", Text: "x"}, + {Type: "variable.declaration", Text: "M"}, + {Type: "property.declaration", Text: "foo"}, + {Type: "property.declaration", Text: "bar"}, + {Type: "variable.declaration", Text: "v"}, + {Type: "namespace", Text: "M"}, + {Type: "interface", Text: "I"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "namespace", Text: "M"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName2_test.go b/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName2_test.go new file mode 100644 index 0000000000..fa5c4f32b4 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationInstantiatedModuleWithVariableOfSameName2_test.go @@ -0,0 +1,46 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationInstantiatedModuleWithVariableOfSameName2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export interface /*1*/I { + } +} + +module /*2*/M { + var x = 10; +} + +var /*3*/M = { + foo: 10, + bar: 20 +} + +var v: /*4*/M./*5*/I; + +var x = /*6*/M;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "namespace.declaration", Text: "M"}, + {Type: "variable.declaration.local", Text: "x"}, + {Type: "variable.declaration", Text: "M"}, + {Type: "property.declaration", Text: "foo"}, + {Type: "property.declaration", Text: "bar"}, + {Type: "variable.declaration", Text: "v"}, + {Type: "namespace", Text: "M"}, + {Type: "interface", Text: "I"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "namespace", Text: "M"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationModules_test.go b/internal/fourslash/tests/gen/semanticClassificationModules_test.go new file mode 100644 index 0000000000..8f85e1ec8c --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationModules_test.go @@ -0,0 +1,35 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationModules(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export var v; + export interface /*1*/I { + } +} + +var x: /*2*/M./*3*/I = /*4*/M.v; +var y = /*5*/M;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "variable.declaration.local", Text: "v"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "namespace", Text: "M"}, + {Type: "interface", Text: "I"}, + {Type: "namespace", Text: "M"}, + {Type: "variable.local", Text: "v"}, + {Type: "variable.declaration", Text: "y"}, + {Type: "namespace", Text: "M"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName1_test.go b/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName1_test.go new file mode 100644 index 0000000000..f7d547d245 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName1_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationUninstantiatedModuleWithVariableOfSameName1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `declare module /*0*/M { + interface /*1*/I { + + } +} + +var M = { I: 10 };` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "variable.declaration", Text: "M"}, + {Type: "property.declaration", Text: "I"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName2_test.go b/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName2_test.go new file mode 100644 index 0000000000..22fc560706 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationUninstantiatedModuleWithVariableOfSameName2_test.go @@ -0,0 +1,40 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationUninstantiatedModuleWithVariableOfSameName2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export interface /*1*/I { + } +} + +var /*2*/M = { + foo: 10, + bar: 20 +} + +var v: /*3*/M./*4*/I; + +var x = /*5*/M;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "variable.declaration", Text: "M"}, + {Type: "property.declaration", Text: "foo"}, + {Type: "property.declaration", Text: "bar"}, + {Type: "variable.declaration", Text: "v"}, + {Type: "variable", Text: "M"}, + {Type: "interface", Text: "I"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "variable", Text: "M"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificationWithUnionTypes_test.go b/internal/fourslash/tests/gen/semanticClassificationWithUnionTypes_test.go new file mode 100644 index 0000000000..41b09590a9 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificationWithUnionTypes_test.go @@ -0,0 +1,41 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationWithUnionTypes(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `module /*0*/M { + export interface /*1*/I { + } +} + +interface /*2*/I { +} +class /*3*/C { +} + +var M: /*4*/M./*5*/I | /*6*/I | /*7*/C; +var I: typeof M | typeof /*8*/C;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable", Text: "M"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "class.declaration", Text: "C"}, + {Type: "variable.declaration", Text: "M"}, + {Type: "variable", Text: "M"}, + {Type: "interface", Text: "I"}, + {Type: "interface", Text: "I"}, + {Type: "class", Text: "C"}, + {Type: "class.declaration", Text: "I"}, + {Type: "variable", Text: "M"}, + {Type: "class", Text: "C"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticClassificatonTypeAlias_test.go b/internal/fourslash/tests/gen/semanticClassificatonTypeAlias_test.go new file mode 100644 index 0000000000..af1b77a746 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticClassificatonTypeAlias_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificatonTypeAlias(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `type /*0*/Alias = number +var x: /*1*/Alias; +var y = {}; +function f(x: /*3*/Alias): /*4*/Alias { return undefined; }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "type.declaration", Text: "Alias"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "type", Text: "Alias"}, + {Type: "variable.declaration", Text: "y"}, + {Type: "type", Text: "Alias"}, + {Type: "function.declaration", Text: "f"}, + {Type: "parameter.declaration", Text: "x"}, + {Type: "type", Text: "Alias"}, + {Type: "type", Text: "Alias"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables2_test.go b/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables2_test.go new file mode 100644 index 0000000000..f208cfe259 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables2_test.go @@ -0,0 +1,38 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationCallableVariables2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `import "node"; +var fs = require("fs") +require.resolve('react'); +require.resolve.paths; +interface LanguageMode { getFoldingRanges?: (d: string) => number[]; }; +function (mode: LanguageMode | undefined) { if (mode && mode.getFoldingRanges) { return mode.getFoldingRanges('a'); }}; +function b(a: () => void) { a(); };` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "fs"}, + {Type: "interface.declaration", Text: "LanguageMode"}, + {Type: "method.declaration", Text: "getFoldingRanges"}, + {Type: "parameter.declaration", Text: "d"}, + {Type: "parameter.declaration", Text: "mode"}, + {Type: "interface", Text: "LanguageMode"}, + {Type: "parameter", Text: "mode"}, + {Type: "parameter", Text: "mode"}, + {Type: "method", Text: "getFoldingRanges"}, + {Type: "parameter", Text: "mode"}, + {Type: "method", Text: "getFoldingRanges"}, + {Type: "function.declaration", Text: "b"}, + {Type: "function.declaration", Text: "a"}, + {Type: "function", Text: "a"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables_test.go b/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables_test.go new file mode 100644 index 0000000000..4fe28264cd --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationCallableVariables_test.go @@ -0,0 +1,44 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationCallableVariables(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class A { onEvent: () => void; } +const x = new A().onEvent; +const match = (s: any) => x(); +const other = match; +match({ other }); +interface B = { (): string; }; var b: B +var s: String; +var t: { (): string; foo: string};` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "A"}, + {Type: "method.declaration", Text: "onEvent"}, + {Type: "function.declaration.readonly", Text: "x"}, + {Type: "class", Text: "A"}, + {Type: "method", Text: "onEvent"}, + {Type: "function.declaration.readonly", Text: "match"}, + {Type: "parameter.declaration", Text: "s"}, + {Type: "function.readonly", Text: "x"}, + {Type: "function.declaration.readonly", Text: "other"}, + {Type: "function.readonly", Text: "match"}, + {Type: "function.readonly", Text: "match"}, + {Type: "method.declaration", Text: "other"}, + {Type: "interface.declaration", Text: "B"}, + {Type: "variable.declaration", Text: "b"}, + {Type: "interface", Text: "B"}, + {Type: "variable.declaration", Text: "s"}, + {Type: "interface.defaultLibrary", Text: "String"}, + {Type: "variable.declaration", Text: "t"}, + {Type: "property.declaration", Text: "foo"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationClassProperties_test.go b/internal/fourslash/tests/gen/semanticModernClassificationClassProperties_test.go new file mode 100644 index 0000000000..2849159725 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationClassProperties_test.go @@ -0,0 +1,34 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationClassProperties(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class A { + private y: number; + constructor(public x : number, _y : number) { this.y = _y; } + get z() : number { return this.x + this.y; } + set a(v: number) { } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "A"}, + {Type: "property.declaration", Text: "y"}, + {Type: "parameter.declaration", Text: "x"}, + {Type: "parameter.declaration", Text: "_y"}, + {Type: "property", Text: "y"}, + {Type: "parameter", Text: "_y"}, + {Type: "property.declaration", Text: "z"}, + {Type: "property", Text: "x"}, + {Type: "property", Text: "y"}, + {Type: "property.declaration", Text: "a"}, + {Type: "parameter.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationConstructorTypes_test.go b/internal/fourslash/tests/gen/semanticModernClassificationConstructorTypes_test.go new file mode 100644 index 0000000000..625ce7da36 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationConstructorTypes_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationConstructorTypes(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `Object.create(null); +const x = Promise.resolve(Number.MAX_VALUE); +if (x instanceof Promise) {}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.defaultLibrary", Text: "Object"}, + {Type: "method.defaultLibrary", Text: "create"}, + {Type: "variable.declaration.readonly", Text: "x"}, + {Type: "class.defaultLibrary", Text: "Number"}, + {Type: "property.readonly.defaultLibrary", Text: "MAX_VALUE"}, + {Type: "variable.readonly", Text: "x"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationInfinityAndNaN_test.go b/internal/fourslash/tests/gen/semanticModernClassificationInfinityAndNaN_test.go new file mode 100644 index 0000000000..e840048a70 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationInfinityAndNaN_test.go @@ -0,0 +1,48 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationInfinityAndNaN(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = ` Infinity; + NaN; + +// Regular properties + +const obj1 = { + Infinity: 100, + NaN: 200, + "-Infinity": 300 +}; + +obj1.Infinity; +obj1.NaN; +obj1["-Infinity"]; + +// Shorthand properties + +const obj2 = { + Infinity, + NaN, +} + +obj2.Infinity; +obj2.NaN;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration.readonly", Text: "obj1"}, + {Type: "variable.readonly", Text: "obj1"}, + {Type: "variable.readonly", Text: "obj1"}, + {Type: "variable.readonly", Text: "obj1"}, + {Type: "variable.declaration.readonly", Text: "obj2"}, + {Type: "variable.readonly", Text: "obj2"}, + {Type: "variable.readonly", Text: "obj2"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationInterfaces_test.go b/internal/fourslash/tests/gen/semanticModernClassificationInterfaces_test.go new file mode 100644 index 0000000000..dd80f8ac7b --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationInterfaces_test.go @@ -0,0 +1,34 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationInterfaces(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `interface Pos { x: number, y: number }; +const p = { x: 1, y: 2 } as Pos; +const foo = (o: Pos) => o.x + o.y;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "interface.declaration", Text: "Pos"}, + {Type: "property.declaration", Text: "x"}, + {Type: "property.declaration", Text: "y"}, + {Type: "variable.declaration.readonly", Text: "p"}, + {Type: "property.declaration", Text: "x"}, + {Type: "property.declaration", Text: "y"}, + {Type: "interface", Text: "Pos"}, + {Type: "function.declaration.readonly", Text: "foo"}, + {Type: "parameter.declaration", Text: "o"}, + {Type: "interface", Text: "Pos"}, + {Type: "parameter", Text: "o"}, + {Type: "property", Text: "x"}, + {Type: "parameter", Text: "o"}, + {Type: "property", Text: "y"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationMembers_test.go b/internal/fourslash/tests/gen/semanticModernClassificationMembers_test.go new file mode 100644 index 0000000000..2131cf7f78 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationMembers_test.go @@ -0,0 +1,37 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationMembers(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class A { + static x = 9; + f = 9; + async m() { return A.x + await this.m(); }; + get s() { return this.f; + static t() { return new A().f; }; + constructor() {} +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "A"}, + {Type: "property.declaration.static", Text: "x"}, + {Type: "property.declaration", Text: "f"}, + {Type: "method.declaration.async", Text: "m"}, + {Type: "class", Text: "A"}, + {Type: "property.static", Text: "x"}, + {Type: "method.async", Text: "m"}, + {Type: "property.declaration", Text: "s"}, + {Type: "property", Text: "f"}, + {Type: "method.declaration.static", Text: "t"}, + {Type: "class", Text: "A"}, + {Type: "property", Text: "f"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationObjectProperties_test.go b/internal/fourslash/tests/gen/semanticModernClassificationObjectProperties_test.go new file mode 100644 index 0000000000..f8419c7525 --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationObjectProperties_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationObjectProperties(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `let x = 1, y = 1; +const a1 = { e: 1 }; +var a2 = { x };` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "x"}, + {Type: "variable.declaration", Text: "y"}, + {Type: "variable.declaration.readonly", Text: "a1"}, + {Type: "property.declaration", Text: "e"}, + {Type: "variable.declaration", Text: "a2"}, + {Type: "property.declaration", Text: "x"}, + }) +} diff --git a/internal/fourslash/tests/gen/semanticModernClassificationVariables_test.go b/internal/fourslash/tests/gen/semanticModernClassificationVariables_test.go new file mode 100644 index 0000000000..be892f667d --- /dev/null +++ b/internal/fourslash/tests/gen/semanticModernClassificationVariables_test.go @@ -0,0 +1,32 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationVariables(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = ` var x = 9, y1 = [x]; + try { + for (const s of y1) { x = s } + } catch (e) { + throw y1; + }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "x"}, + {Type: "variable.declaration", Text: "y1"}, + {Type: "variable", Text: "x"}, + {Type: "variable.declaration.readonly.local", Text: "s"}, + {Type: "variable", Text: "y1"}, + {Type: "variable", Text: "x"}, + {Type: "variable.readonly.local", Text: "s"}, + {Type: "variable.declaration.local", Text: "e"}, + {Type: "variable", Text: "y1"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationForJSDocTemplateTag_test.go b/internal/fourslash/tests/gen/syntacticClassificationForJSDocTemplateTag_test.go new file mode 100644 index 0000000000..564378646f --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationForJSDocTemplateTag_test.go @@ -0,0 +1,23 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationForJSDocTemplateTag(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** @template T baring strait */ +function ident: T { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "function.declaration", Text: "ident"}, + {Type: "typeParameter.declaration", Text: "T"}, + {Type: "typeParameter", Text: "T"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationWithErrors_test.go b/internal/fourslash/tests/gen/syntacticClassificationWithErrors_test.go new file mode 100644 index 0000000000..0c19c22edb --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationWithErrors_test.go @@ -0,0 +1,23 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationWithErrors(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class A { + a: +} +c =` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "A"}, + {Type: "property.declaration", Text: "a"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassifications1_test.go b/internal/fourslash/tests/gen/syntacticClassifications1_test.go new file mode 100644 index 0000000000..c6777efe8c --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassifications1_test.go @@ -0,0 +1,43 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassifications1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// comment +module M { + var v = 0 + 1; + var s = "string"; + + class C { + } + + enum E { + } + + interface I { + } + + module M1.M2 { + } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "namespace.declaration", Text: "M"}, + {Type: "variable.declaration.local", Text: "v"}, + {Type: "variable.declaration.local", Text: "s"}, + {Type: "class.declaration", Text: "C"}, + {Type: "typeParameter.declaration", Text: "T"}, + {Type: "enum.declaration", Text: "E"}, + {Type: "interface.declaration", Text: "I"}, + {Type: "namespace.declaration", Text: "M1"}, + {Type: "namespace.declaration", Text: "M2"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers1_test.go new file mode 100644 index 0000000000..a0515370b0 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers1_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsConflictDiff3Markers1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class C { +<<<<<<< HEAD + v = 1; +||||||| merged common ancestors + v = 3; +======= + v = 2; +>>>>>>> Branch - a +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "C"}, + {Type: "property.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers2_test.go new file mode 100644 index 0000000000..9f077e27a2 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsConflictDiff3Markers2_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsConflictDiff3Markers2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `<<<<<<< HEAD +class C { } +||||||| merged common ancestors +class E { } +======= +class D { } +>>>>>>> Branch - a` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "C"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers1_test.go new file mode 100644 index 0000000000..135947355a --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers1_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsConflictMarkers1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class C { +<<<<<<< HEAD + v = 1; +======= + v = 2; +>>>>>>> Branch - a +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "C"}, + {Type: "property.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers2_test.go new file mode 100644 index 0000000000..78c0c3265c --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsConflictMarkers2_test.go @@ -0,0 +1,23 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsConflictMarkers2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `<<<<<<< HEAD +class C { } +======= +class D { } +>>>>>>> Branch - a` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "class.declaration", Text: "C"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsDocComment1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsDocComment1_test.go new file mode 100644 index 0000000000..c2af43288f --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsDocComment1_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsDocComment1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** @type {number} */ +var v;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsDocComment2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsDocComment2_test.go new file mode 100644 index 0000000000..e5c22d53c4 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsDocComment2_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsDocComment2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** @param foo { function(x): string } */ +var v;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsDocComment3_test.go b/internal/fourslash/tests/gen/syntacticClassificationsDocComment3_test.go new file mode 100644 index 0000000000..a97f441a34 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsDocComment3_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsDocComment3(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** @param foo { number /* } */ +var v;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsDocComment4_test.go b/internal/fourslash/tests/gen/syntacticClassificationsDocComment4_test.go new file mode 100644 index 0000000000..39b2818d2f --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsDocComment4_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsDocComment4(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** @param {number} p1 */ +function foo(p1) {}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "function.declaration", Text: "foo"}, + {Type: "parameter.declaration", Text: "p1"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword2_test.go new file mode 100644 index 0000000000..9caf091dcf --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword2_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsForOfKeyword2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `for (var of in of) { }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "of"}, + {Type: "variable", Text: "of"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword3_test.go b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword3_test.go new file mode 100644 index 0000000000..e9b25dad85 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword3_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsForOfKeyword3(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `for (var of; of; of) { }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "of"}, + {Type: "variable", Text: "of"}, + {Type: "variable", Text: "of"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword_test.go b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword_test.go new file mode 100644 index 0000000000..79a3c567c5 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsForOfKeyword_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsForOfKeyword(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `for (var of of of) { }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "of"}, + {Type: "variable", Text: "of"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsFunctionWithComments_test.go b/internal/fourslash/tests/gen/syntacticClassificationsFunctionWithComments_test.go new file mode 100644 index 0000000000..30d904a07e --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsFunctionWithComments_test.go @@ -0,0 +1,31 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsFunctionWithComments(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `/** + * This is my function. + * There are many like it, but this one is mine. + */ +function myFunction(/* x */ x: any) { + var y = x ? x++ : ++x; +} +// end of file` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "function.declaration", Text: "myFunction"}, + {Type: "parameter.declaration", Text: "x"}, + {Type: "variable.declaration.local", Text: "y"}, + {Type: "parameter", Text: "x"}, + {Type: "parameter", Text: "x"}, + {Type: "parameter", Text: "x"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsJsx1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsJsx1_test.go new file mode 100644 index 0000000000..7368082074 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsJsx1_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsJsx1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: file1.tsx +let x =
+ some jsx text +
; + +let y = ` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "x"}, + {Type: "variable.declaration", Text: "y"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsJsx2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsJsx2_test.go new file mode 100644 index 0000000000..fafe59372d --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsJsx2_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsJsx2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: file1.tsx +let x = + some jsx text +; + +let y = ` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "x"}, + {Type: "variable.declaration", Text: "y"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsMergeConflictMarker1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsMergeConflictMarker1_test.go new file mode 100644 index 0000000000..8185f8aa3b --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsMergeConflictMarker1_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsMergeConflictMarker1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `<<<<<<< HEAD +"AAAA" +======= +"BBBB" +>>>>>>> Feature` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{}) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsObjectLiteral_test.go b/internal/fourslash/tests/gen/syntacticClassificationsObjectLiteral_test.go new file mode 100644 index 0000000000..ae5da78faa --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsObjectLiteral_test.go @@ -0,0 +1,38 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsObjectLiteral(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `var v = 10e0; +var x = { + p1: 1, + p2: 2, + any: 3, + function: 4, + var: 5, + void: void 0, + v: v += v, +};` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "v"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "property.declaration", Text: "p1"}, + {Type: "property.declaration", Text: "p2"}, + {Type: "property.declaration", Text: "any"}, + {Type: "property.declaration", Text: "function"}, + {Type: "property.declaration", Text: "var"}, + {Type: "property.declaration", Text: "void"}, + {Type: "property.declaration", Text: "v"}, + {Type: "variable", Text: "v"}, + {Type: "variable", Text: "v"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsTemplates1_test.go b/internal/fourslash/tests/gen/syntacticClassificationsTemplates1_test.go new file mode 100644 index 0000000000..8c394d46f9 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsTemplates1_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsTemplates1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `var v = 10e0; +var x = { + p1: ` + "`" + `hello world` + "`" + `, + p2: ` + "`" + `goodbye ${0} cruel ${0} world` + "`" + `, +};` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "v"}, + {Type: "variable.declaration", Text: "x"}, + {Type: "property.declaration", Text: "p1"}, + {Type: "property.declaration", Text: "p2"}, + }) +} diff --git a/internal/fourslash/tests/gen/syntacticClassificationsTemplates2_test.go b/internal/fourslash/tests/gen/syntacticClassificationsTemplates2_test.go new file mode 100644 index 0000000000..cfb65d64e8 --- /dev/null +++ b/internal/fourslash/tests/gen/syntacticClassificationsTemplates2_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSyntacticClassificationsTemplates2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `var tiredOfCanonicalExamples = +` + "`" + `goodbye "${ ` + "`" + `hello world` + "`" + ` }" +and ${ ` + "`" + `good${ " " }riddance` + "`" + ` }` + "`" + `;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "variable.declaration", Text: "tiredOfCanonicalExamples"}, + }) +} diff --git a/internal/fourslash/tests/manual/semanticModernClassificationFunctions_test.go b/internal/fourslash/tests/manual/semanticModernClassificationFunctions_test.go new file mode 100644 index 0000000000..648f9f5076 --- /dev/null +++ b/internal/fourslash/tests/manual/semanticModernClassificationFunctions_test.go @@ -0,0 +1,34 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticModernClassificationFunctions(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo(p1) { + return foo(Math.abs(p1)) +} +` + "`" + `/${window.location}` + "`" + `.split("/").forEach(s => foo(s));` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "function.declaration", Text: "foo"}, + {Type: "parameter.declaration", Text: "p1"}, + {Type: "function", Text: "foo"}, + {Type: "variable.defaultLibrary", Text: "Math"}, + {Type: "method.defaultLibrary", Text: "abs"}, + {Type: "parameter", Text: "p1"}, + {Type: "variable.defaultLibrary", Text: "window"}, + {Type: "property.defaultLibrary", Text: "location"}, + {Type: "method.defaultLibrary", Text: "split"}, + {Type: "method.defaultLibrary", Text: "forEach"}, + {Type: "parameter.declaration", Text: "s"}, + {Type: "function", Text: "foo"}, + {Type: "parameter", Text: "s"}, + }) +} diff --git a/internal/fourslash/tests/semanticClassificationJSX_test.go b/internal/fourslash/tests/semanticClassificationJSX_test.go new file mode 100644 index 0000000000..6298471045 --- /dev/null +++ b/internal/fourslash/tests/semanticClassificationJSX_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSemanticClassificationJSX(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.tsx +const Component = () =>
Hello
; +const afterJSX = 42; +const alsoAfterJSX = "test";` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/a.tsx") + f.VerifySemanticTokens(t, []fourslash.SemanticToken{ + {Type: "function.declaration.readonly", Text: "Component"}, + {Type: "variable.declaration.readonly", Text: "afterJSX"}, + {Type: "variable.declaration.readonly", Text: "alsoAfterJSX"}, + }) +} diff --git a/internal/ls/semantictokens.go b/internal/ls/semantictokens.go new file mode 100644 index 0000000000..3554d9f03a --- /dev/null +++ b/internal/ls/semantictokens.go @@ -0,0 +1,580 @@ +package ls + +import ( + "context" + "fmt" + "slices" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/checker" + "github.com/microsoft/typescript-go/internal/compiler" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/ls/lsconv" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/scanner" + "github.com/microsoft/typescript-go/internal/tspath" +) + +// tokenTypes defines the order of token types for encoding +var tokenTypes = []lsproto.SemanticTokenTypes{ + lsproto.SemanticTokenTypesnamespace, + lsproto.SemanticTokenTypesclass, + lsproto.SemanticTokenTypesenum, + lsproto.SemanticTokenTypesinterface, + lsproto.SemanticTokenTypesstruct, + lsproto.SemanticTokenTypestypeParameter, + lsproto.SemanticTokenTypestype, + lsproto.SemanticTokenTypesparameter, + lsproto.SemanticTokenTypesvariable, + lsproto.SemanticTokenTypesproperty, + lsproto.SemanticTokenTypesenumMember, + lsproto.SemanticTokenTypesdecorator, + lsproto.SemanticTokenTypesevent, + lsproto.SemanticTokenTypesfunction, + lsproto.SemanticTokenTypesmethod, + lsproto.SemanticTokenTypesmacro, + lsproto.SemanticTokenTypeslabel, + lsproto.SemanticTokenTypescomment, + lsproto.SemanticTokenTypesstring, + lsproto.SemanticTokenTypeskeyword, + lsproto.SemanticTokenTypesnumber, + lsproto.SemanticTokenTypesregexp, + lsproto.SemanticTokenTypesoperator, +} + +// tokenModifiers defines the order of token modifiers for encoding +var tokenModifiers = []lsproto.SemanticTokenModifiers{ + lsproto.SemanticTokenModifiersdeclaration, + lsproto.SemanticTokenModifiersdefinition, + lsproto.SemanticTokenModifiersreadonly, + lsproto.SemanticTokenModifiersstatic, + lsproto.SemanticTokenModifiersdeprecated, + lsproto.SemanticTokenModifiersabstract, + lsproto.SemanticTokenModifiersasync, + lsproto.SemanticTokenModifiersmodification, + lsproto.SemanticTokenModifiersdocumentation, + lsproto.SemanticTokenModifiersdefaultLibrary, + "local", +} + +type tokenType int + +const ( + tokenTypeNamespace tokenType = iota + tokenTypeClass + tokenTypeEnum + tokenTypeInterface + tokenTypeStruct + tokenTypeTypeParameter + tokenTypeType + tokenTypeParameter + tokenTypeVariable + tokenTypeProperty + tokenTypeEnumMember + tokenTypeDecorator + tokenTypeEvent + tokenTypeFunction + tokenTypeMethod // Previously called "member" in TypeScript + tokenTypeMacro + tokenTypeLabel + tokenTypeComment + tokenTypeString + tokenTypeKeyword + tokenTypeNumber + tokenTypeRegexp + tokenTypeOperator +) + +type tokenModifier int + +const ( + tokenModifierDeclaration tokenModifier = 1 << iota + tokenModifierDefinition + tokenModifierReadonly + tokenModifierStatic + tokenModifierDeprecated + tokenModifierAbstract + tokenModifierAsync + tokenModifierModification + tokenModifierDocumentation + tokenModifierDefaultLibrary + tokenModifierLocal +) + +// SemanticTokensLegend returns the legend describing the token types and modifiers. +// If clientCapabilities is provided, it filters the legend to only include types and modifiers +// that the client supports. +func SemanticTokensLegend(clientCapabilities *lsproto.SemanticTokensClientCapabilities) *lsproto.SemanticTokensLegend { + types := make([]string, 0, len(tokenTypes)) + for _, t := range tokenTypes { + if clientCapabilities == nil || slices.Contains(clientCapabilities.TokenTypes, string(t)) { + types = append(types, string(t)) + } + } + modifiers := make([]string, 0, len(tokenModifiers)) + for _, m := range tokenModifiers { + if clientCapabilities == nil || slices.Contains(clientCapabilities.TokenModifiers, string(m)) { + modifiers = append(modifiers, string(m)) + } + } + return &lsproto.SemanticTokensLegend{ + TokenTypes: types, + TokenModifiers: modifiers, + } +} + +func (l *LanguageService) ProvideSemanticTokens(ctx context.Context, documentURI lsproto.DocumentUri, clientCapabilities *lsproto.SemanticTokensClientCapabilities) (lsproto.SemanticTokensResponse, error) { + program, file := l.getProgramAndFile(documentURI) + + c, done := program.GetTypeCheckerForFile(ctx, file) + defer done() + + tokens := l.collectSemanticTokens(ctx, c, file, program) + + if len(tokens) == 0 { + return lsproto.SemanticTokensOrNull{}, nil + } + + // Convert to LSP format (relative encoding) + encoded := encodeSemanticTokens(tokens, file, l.converters, clientCapabilities) + + return lsproto.SemanticTokensOrNull{ + SemanticTokens: &lsproto.SemanticTokens{ + Data: encoded, + }, + }, nil +} + +func (l *LanguageService) ProvideSemanticTokensRange(ctx context.Context, documentURI lsproto.DocumentUri, rang lsproto.Range, clientCapabilities *lsproto.SemanticTokensClientCapabilities) (lsproto.SemanticTokensRangeResponse, error) { + program, file := l.getProgramAndFile(documentURI) + + c, done := program.GetTypeCheckerForFile(ctx, file) + defer done() + + start := int(l.converters.LineAndCharacterToPosition(file, rang.Start)) + end := int(l.converters.LineAndCharacterToPosition(file, rang.End)) + + tokens := l.collectSemanticTokensInRange(ctx, c, file, program, start, end) + + if len(tokens) == 0 { + return lsproto.SemanticTokensOrNull{}, nil + } + + // Convert to LSP format (relative encoding) + encoded := encodeSemanticTokens(tokens, file, l.converters, clientCapabilities) + + return lsproto.SemanticTokensOrNull{ + SemanticTokens: &lsproto.SemanticTokens{ + Data: encoded, + }, + }, nil +} + +type semanticToken struct { + node *ast.Node + tokenType tokenType + tokenModifier tokenModifier +} + +func (l *LanguageService) collectSemanticTokens(ctx context.Context, c *checker.Checker, file *ast.SourceFile, program *compiler.Program) []semanticToken { + return l.collectSemanticTokensInRange(ctx, c, file, program, file.Pos(), file.End()) +} + +func (l *LanguageService) collectSemanticTokensInRange(ctx context.Context, c *checker.Checker, file *ast.SourceFile, program *compiler.Program, spanStart, spanEnd int) []semanticToken { + tokens := []semanticToken{} + + inJSXElement := false + + var visit func(*ast.Node) bool + visit = func(node *ast.Node) bool { + // Check for cancellation + if ctx.Err() != nil { + return false + } + + if node == nil { + return false + } + nodeEnd := node.End() + if node.Pos() >= spanEnd || nodeEnd <= spanStart { + return false + } + + prevInJSXElement := inJSXElement + if ast.IsJsxElement(node) || ast.IsJsxSelfClosingElement(node) { + inJSXElement = true + } else if ast.IsJsxExpression(node) { + inJSXElement = false + } + + if ast.IsIdentifier(node) && node.Text() != "" && !inJSXElement && !isInImportClause(node) && !isInfinityOrNaNString(node.Text()) { + symbol := c.GetSymbolAtLocation(node) + if symbol != nil { + // Resolve aliases + if symbol.Flags&ast.SymbolFlagsAlias != 0 { + symbol = c.GetAliasedSymbol(symbol) + } + + tokenType, ok := classifySymbol(symbol, getMeaningFromLocation(node)) + if ok { + tokenModifier := tokenModifier(0) + + // Check if this is a declaration + parent := node.Parent + if parent != nil { + parentIsDeclaration := ast.IsBindingElement(parent) || tokenFromDeclarationMapping(parent.Kind) == tokenType + if parentIsDeclaration && parent.Name() == node { + tokenModifier |= tokenModifierDeclaration + } + } + + // Property declaration in constructor: reclassify parameters as properties in property access context + if tokenType == tokenTypeParameter && ast.IsRightSideOfQualifiedNameOrPropertyAccess(node) { + tokenType = tokenTypeProperty + } + + // Type-based reclassification + tokenType = reclassifyByType(c, node, tokenType) + + // Get the value declaration to check modifiers + if decl := symbol.ValueDeclaration; decl != nil { + modifiers := ast.GetCombinedModifierFlags(decl) + nodeFlags := ast.GetCombinedNodeFlags(decl) + + if modifiers&ast.ModifierFlagsStatic != 0 { + tokenModifier |= tokenModifierStatic + } + if modifiers&ast.ModifierFlagsAsync != 0 { + tokenModifier |= tokenModifierAsync + } + if tokenType != tokenTypeClass && tokenType != tokenTypeInterface { + if (modifiers&ast.ModifierFlagsReadonly != 0) || (nodeFlags&ast.NodeFlagsConst != 0) || (symbol.Flags&ast.SymbolFlagsEnumMember != 0) { + tokenModifier |= tokenModifierReadonly + } + } + if (tokenType == tokenTypeVariable || tokenType == tokenTypeFunction) && isLocalDeclaration(decl, file) { + tokenModifier |= tokenModifierLocal + } + declSourceFile := ast.GetSourceFileOfNode(decl) + if declSourceFile != nil && program.IsSourceFileDefaultLibrary(tspath.Path(declSourceFile.FileName())) { + tokenModifier |= tokenModifierDefaultLibrary + } + } else if symbol.Declarations != nil { + for _, decl := range symbol.Declarations { + declSourceFile := ast.GetSourceFileOfNode(decl) + if declSourceFile != nil && program.IsSourceFileDefaultLibrary(tspath.Path(declSourceFile.FileName())) { + tokenModifier |= tokenModifierDefaultLibrary + break + } + } + } + + tokens = append(tokens, semanticToken{ + node: node, + tokenType: tokenType, + tokenModifier: tokenModifier, + }) + } + } + } + + node.ForEachChild(visit) + inJSXElement = prevInJSXElement + return false + } + + visit(file.AsNode()) + + // Check for cancellation after collection + if ctx.Err() != nil { + return nil + } + + return tokens +} + +func classifySymbol(symbol *ast.Symbol, meaning ast.SemanticMeaning) (tokenType, bool) { + flags := symbol.Flags + if flags&ast.SymbolFlagsClass != 0 { + return tokenTypeClass, true + } + if flags&ast.SymbolFlagsEnum != 0 { + return tokenTypeEnum, true + } + if flags&ast.SymbolFlagsTypeAlias != 0 { + return tokenTypeType, true + } + if flags&ast.SymbolFlagsInterface != 0 { + if meaning&ast.SemanticMeaningType != 0 { + return tokenTypeInterface, true + } + } + if flags&ast.SymbolFlagsTypeParameter != 0 { + return tokenTypeTypeParameter, true + } + + // Check the value declaration + decl := symbol.ValueDeclaration + if decl == nil && len(symbol.Declarations) > 0 { + decl = symbol.Declarations[0] + } + if decl != nil { + if ast.IsBindingElement(decl) { + decl = getDeclarationForBindingElement(decl) + } + if tokenType := tokenFromDeclarationMapping(decl.Kind); tokenType >= 0 { + return tokenType, true + } + } + + return 0, false +} + +func tokenFromDeclarationMapping(kind ast.Kind) tokenType { + switch kind { + case ast.KindVariableDeclaration: + return tokenTypeVariable + case ast.KindParameter: + return tokenTypeParameter + case ast.KindPropertyDeclaration: + return tokenTypeProperty + case ast.KindModuleDeclaration: + return tokenTypeNamespace + case ast.KindEnumDeclaration: + return tokenTypeEnum + case ast.KindEnumMember: + return tokenTypeEnumMember + case ast.KindClassDeclaration: + return tokenTypeClass + case ast.KindMethodDeclaration: + return tokenTypeMethod + case ast.KindFunctionDeclaration, ast.KindFunctionExpression: + return tokenTypeFunction + case ast.KindMethodSignature: + return tokenTypeMethod + case ast.KindGetAccessor, ast.KindSetAccessor: + return tokenTypeProperty + case ast.KindPropertySignature: + return tokenTypeProperty + case ast.KindInterfaceDeclaration: + return tokenTypeInterface + case ast.KindTypeAliasDeclaration: + return tokenTypeType + case ast.KindTypeParameter: + return tokenTypeTypeParameter + case ast.KindPropertyAssignment, ast.KindShorthandPropertyAssignment: + return tokenTypeProperty + default: + return -1 + } +} + +func reclassifyByType(c *checker.Checker, node *ast.Node, tt tokenType) tokenType { + // Type-based reclassification for variables, properties, and parameters + if tt == tokenTypeVariable || tt == tokenTypeProperty || tt == tokenTypeParameter { + typ := c.GetTypeAtLocation(node) + if typ != nil { + test := func(condition func(*checker.Type) bool) bool { + if condition(typ) { + return true + } + if typ.Flags()&checker.TypeFlagsUnion != 0 { + if slices.ContainsFunc(typ.AsUnionType().Types(), condition) { + return true + } + } + return false + } + + // Check for constructor signatures (class-like) + if tt != tokenTypeParameter && test(func(t *checker.Type) bool { + return len(c.GetSignaturesOfType(t, checker.SignatureKindConstruct)) > 0 + }) { + return tokenTypeClass + } + + // Check for call signatures (function-like) + // Must have call signatures AND (no properties OR be used in call context) + hasCallSignatures := test(func(t *checker.Type) bool { + return len(c.GetSignaturesOfType(t, checker.SignatureKindCall)) > 0 + }) + if hasCallSignatures { + hasNoProperties := !test(func(t *checker.Type) bool { + objType := t.AsObjectType() + return objType != nil && len(objType.Properties()) > 0 + }) + if hasNoProperties || isExpressionInCallExpression(node) { + if tt == tokenTypeProperty { + return tokenTypeMethod + } + return tokenTypeFunction + } + } + } + } + return tt +} + +func isLocalDeclaration(decl *ast.Node, sourceFile *ast.SourceFile) bool { + if ast.IsBindingElement(decl) { + decl = getDeclarationForBindingElement(decl) + } + if ast.IsVariableDeclaration(decl) { + parent := decl.Parent + // Check if this is a catch clause parameter + if parent != nil && ast.IsCatchClause(parent) { + return ast.GetSourceFileOfNode(decl) == sourceFile + } + if parent != nil && ast.IsVariableDeclarationList(parent) { + grandparent := parent.Parent + if grandparent != nil { + greatGrandparent := grandparent.Parent + return (!ast.IsSourceFile(greatGrandparent) || ast.IsCatchClause(grandparent)) && + ast.GetSourceFileOfNode(decl) == sourceFile + } + } + } else if ast.IsFunctionDeclaration(decl) { + parent := decl.Parent + return parent != nil && !ast.IsSourceFile(parent) && ast.GetSourceFileOfNode(decl) == sourceFile + } + return false +} + +func getDeclarationForBindingElement(element *ast.Node) *ast.Node { + for { + parent := element.Parent + if parent != nil && ast.IsBindingPattern(parent) { + grandparent := parent.Parent + if grandparent != nil && ast.IsBindingElement(grandparent) { + element = grandparent + continue + } + return parent.Parent + } + return element + } +} + +func isInImportClause(node *ast.Node) bool { + parent := node.Parent + return parent != nil && (ast.IsImportClause(parent) || ast.IsImportSpecifier(parent) || ast.IsNamespaceImport(parent)) +} + +func isExpressionInCallExpression(node *ast.Node) bool { + for ast.IsRightSideOfQualifiedNameOrPropertyAccess(node) { + node = node.Parent + } + parent := node.Parent + return parent != nil && ast.IsCallExpression(parent) && parent.Expression() == node +} + +func isInfinityOrNaNString(text string) bool { + return text == "Infinity" || text == "NaN" +} + +// encodeSemanticTokens encodes tokens into the LSP format using relative positioning. +// It filters tokens based on client capabilities, only including types and modifiers that the client supports. +func encodeSemanticTokens(tokens []semanticToken, file *ast.SourceFile, converters *lsconv.Converters, clientCapabilities *lsproto.SemanticTokensClientCapabilities) []uint32 { + // Build mapping from server token types/modifiers to client indices + typeMapping := make(map[tokenType]uint32) + modifierMapping := make(map[lsproto.SemanticTokenModifiers]uint32) + + if clientCapabilities != nil { + // Map server token types to client-supported indices + clientIdx := uint32(0) + for i, serverType := range tokenTypes { + if slices.Contains(clientCapabilities.TokenTypes, string(serverType)) { + typeMapping[tokenType(i)] = clientIdx + clientIdx++ + } + } + + // Map server token modifiers to client-supported bit positions + clientBit := uint32(0) + for _, serverModifier := range tokenModifiers { + if slices.Contains(clientCapabilities.TokenModifiers, string(serverModifier)) { + modifierMapping[serverModifier] = clientBit + clientBit++ + } + } + } else { + // No filtering - use direct mapping + for i := range tokenTypes { + typeMapping[tokenType(i)] = uint32(i) + } + for i, mod := range tokenModifiers { + modifierMapping[mod] = uint32(i) + } + } + + // Each token encodes 5 uint32 values: deltaLine, deltaChar, length, tokenType, tokenModifiers + encoded := make([]uint32, 0, len(tokens)*5) + prevLine := uint32(0) + prevChar := uint32(0) + + for _, token := range tokens { + // Skip tokens with types not supported by the client + clientTypeIdx, typeSupported := typeMapping[token.tokenType] + if !typeSupported { + continue + } + + // Map modifiers to client-supported bit mask + clientModifierMask := uint32(0) + for i, serverModifier := range tokenModifiers { + if token.tokenModifier&(1< 0 && (line < prevLine || (line == prevLine && char <= prevChar)) { + panic(fmt.Sprintf("semantic tokens: positions must be strictly increasing: prev=(%d,%d) current=(%d,%d) for token at offset %d", + prevLine, prevChar, line, char, tokenStart)) + } + + // Encode as: [deltaLine, deltaChar, length, tokenType, tokenModifiers] + deltaLine := line - prevLine + var deltaChar uint32 + if deltaLine == 0 { + deltaChar = char - prevChar + } else { + deltaChar = char + } + + encoded = append(encoded, + deltaLine, + deltaChar, + tokenLength, + clientTypeIdx, + clientModifierMask, + ) + + prevLine = line + prevChar = char + } + + return encoded +} diff --git a/internal/lsp/server.go b/internal/lsp/server.go index cecd426747..7685b0ce95 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -492,6 +492,8 @@ var handlers = sync.OnceValue(func() handlerMap { registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentSelectionRangeInfo, (*Server).handleSelectionRange) registerRequestHandler(handlers, lsproto.WorkspaceSymbolInfo, (*Server).handleWorkspaceSymbol) registerRequestHandler(handlers, lsproto.CompletionItemResolveInfo, (*Server).handleCompletionItemResolve) + registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentSemanticTokensFullInfo, (*Server).handleSemanticTokensFull) + registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentSemanticTokensRangeInfo, (*Server).handleSemanticTokensRange) return handlers }) @@ -672,6 +674,17 @@ func (s *Server) handleInitialize(ctx context.Context, params *lsproto.Initializ SelectionRangeProvider: &lsproto.BooleanOrSelectionRangeOptionsOrSelectionRangeRegistrationOptions{ Boolean: ptrTo(true), }, + SemanticTokensProvider: &lsproto.SemanticTokensOptionsOrRegistrationOptions{ + Options: &lsproto.SemanticTokensOptions{ + Legend: ls.SemanticTokensLegend(getSemanticTokensClientCapabilities(params)), + Full: &lsproto.BooleanOrSemanticTokensFullDelta{ + Boolean: ptrTo(true), + }, + Range: &lsproto.BooleanOrEmptyObject{ + Boolean: ptrTo(true), + }, + }, + }, }, } @@ -915,6 +928,16 @@ func (s *Server) handleSelectionRange(ctx context.Context, ls *ls.LanguageServic return ls.ProvideSelectionRanges(ctx, params) } +func (s *Server) handleSemanticTokensFull(ctx context.Context, ls *ls.LanguageService, params *lsproto.SemanticTokensParams) (lsproto.SemanticTokensResponse, error) { + clientCapabilities := getSemanticTokensClientCapabilities(s.initializeParams) + return ls.ProvideSemanticTokens(ctx, params.TextDocument.Uri, clientCapabilities) +} + +func (s *Server) handleSemanticTokensRange(ctx context.Context, ls *ls.LanguageService, params *lsproto.SemanticTokensRangeParams) (lsproto.SemanticTokensRangeResponse, error) { + clientCapabilities := getSemanticTokensClientCapabilities(s.initializeParams) + return ls.ProvideSemanticTokensRange(ctx, params.TextDocument.Uri, params.Range, clientCapabilities) +} + func (s *Server) Log(msg ...any) { fmt.Fprintln(s.stderr, msg...) } @@ -968,7 +991,7 @@ func shouldEnableWatch(params *lsproto.InitializeParams) bool { } func getCompletionClientCapabilities(params *lsproto.InitializeParams) *lsproto.CompletionClientCapabilities { - if params == nil || params.Capabilities == nil || params.Capabilities.TextDocument == nil { + if params.Capabilities == nil || params.Capabilities.TextDocument == nil { return nil } return params.Capabilities.TextDocument.Completion @@ -1058,3 +1081,10 @@ func getDiagnosticClientCapabilities(params *lsproto.InitializeParams) *lsproto. return &caps } + +func getSemanticTokensClientCapabilities(params *lsproto.InitializeParams) *lsproto.SemanticTokensClientCapabilities { + if params.Capabilities == nil || params.Capabilities.TextDocument == nil { + return nil + } + return params.Capabilities.TextDocument.SemanticTokens +} diff --git a/testdata/baselines/reference/fourslash/documentHighlights/renameDefaultImport.baseline.jsonc b/testdata/baselines/reference/fourslash/documentHighlights/renameDefaultImport.baseline.jsonc new file mode 100644 index 0000000000..0f348b352d --- /dev/null +++ b/testdata/baselines/reference/fourslash/documentHighlights/renameDefaultImport.baseline.jsonc @@ -0,0 +1,6 @@ +// === documentHighlights === +// === /B.ts === +// export default class /*HIGHLIGHTS*/[|B|] { +// test() { +// } +// } \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/findAllReferences/renameDefaultImport.baseline.jsonc b/testdata/baselines/reference/fourslash/findAllReferences/renameDefaultImport.baseline.jsonc new file mode 100644 index 0000000000..6933ed8935 --- /dev/null +++ b/testdata/baselines/reference/fourslash/findAllReferences/renameDefaultImport.baseline.jsonc @@ -0,0 +1,25 @@ +// === findAllReferences === +// === /A.ts === +// import [|B|] from "./B"; +// let b = new [|B|](); +// b.test(); + +// === /B.ts === +// export default class /*FIND ALL REFS*/[|B|] { +// test() { +// } +// } + + + +// === findAllReferences === +// === /A.ts === +// import /*FIND ALL REFS*/[|B|] from "./B"; +// let b = new [|B|](); +// b.test(); + +// === /B.ts === +// export default class [|B|] { +// test() { +// } +// } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc new file mode 100644 index 0000000000..55265b7c8e --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc @@ -0,0 +1,27 @@ +// === findRenameLocations === +// === /A.ts === +// import [|BRENAME|] from "./B"; +// let b = new [|BRENAME|](); +// b.test(); + +// === /B.ts === +// export default class /*RENAME*/[|BRENAME|] { +// test() { +// } +// } + + + +// === findRenameLocations === +// === /A.ts === +// import /*RENAME*/[|BRENAME|] from "./B"; +// let b = new [|BRENAME|](); +// b.test(); + + + +// === findRenameLocations === +// === /A.ts === +// import [|BRENAME|] from "./B"; +// let b = new /*RENAME*/[|BRENAME|](); +// b.test(); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc.diff new file mode 100644 index 0000000000..32d6d701c7 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/findRenameLocations/renameDefaultImport.baseline.jsonc.diff @@ -0,0 +1,29 @@ +--- old.renameDefaultImport.baseline.jsonc ++++ new.renameDefaultImport.baseline.jsonc +@@= skipped -0, +0 lines =@@ + // === findRenameLocations === ++// === /A.ts === ++// import [|BRENAME|] from "./B"; ++// let b = new [|BRENAME|](); ++// b.test(); ++ + // === /B.ts === + // export default class /*RENAME*/[|BRENAME|] { + // test() { + // } + // } + +-// === /A.ts === +-// import [|BRENAME|] from "./B"; +-// let b = new [|BRENAME|](); +-// b.test(); +- + + + // === findRenameLocations === +@@= skipped -24, +24 lines =@@ + // import [|BRENAME|] from "./B"; + // let b = new /*RENAME*/[|BRENAME|](); + // b.test(); +- +- \ No newline at end of file