vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

View File

@@ -0,0 +1,20 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestGoToDefinitionDecoratorNoCrashOnFunctionDeclaration1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `function dec(target: any) { return target; }
@/*1*/dec
function foo() {}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineGoToDefinition(t, true, "1")
}

View File

@@ -0,0 +1,41 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestArgumentCompletions(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
function foo(a: "a", b: "b") {}
foo("a", /*1*/);
const t3 = ['x', 'y', 'z'] as const;
const x: [string, string, string, 'a' | 'b'] = [...t3, /*2*/];
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{`"b"`},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{`"b"`},
},
})
}

View File

@@ -0,0 +1,98 @@
package fourslash
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoCloseTagsWithTriviaAndComplexNames(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
// Using separate files for each example to avoid unclosed JSX tags affecting other tests.
const content = `// @noLib: true
// @Filename: /0.tsx
// JSDoc
const x = <
/** hello world! */
div /** hello world! */
>/*0*/
// @Filename: /1.tsx
// Single-line comments
const x =
<
// hello world!
div // hello world!
>/*1*/
// @Filename: /2.tsx
// Namespaced tag
const x =
<ns:sometag>/*2*/
// @Filename: /3.tsx
// Namespace with single-line comments
const x = <
// pre-ns
ns
// pre-colon
:
// post-colon
sometag
// post-id
>/*3*/
// @Filename: /4.tsx
// UppercaseComponent-named tag
const x = <SomeComponent>/*4*/
// @Filename: /5.tsx
// propertyAccess.Component-named tag
const x = <
someModule
.
SomeComponent
>/*5*/
// @Filename: /6.tsx
// propertyAccess.Component-named tag with single-line comments
const x =
<
// pre-object
someModule
// pre-dot
.
// post-dot
SomeComponent
// post-id
>/*6*/;
// @Filename: /7.tsx
// Generic propertyAccess.Component-named tag
const x =
<
someModule.SomeComponent<string>
prop="stringValue"
>/*7*/;
// @Filename: /8.tsx
// Namespaced tag with hyphens
const x =
<my-namespace:my-tag>/*8*/
// @Filename: /9.tsx
// Generic tag with no attributes
const x = <SomeComponent<number>>/*9*/
// @Filename: /10.tsx
// Tag name containing $ (must be snippet-escaped)
const x = <$Foo>/*10*/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineClosingTags(t)
}

View File

@@ -0,0 +1,105 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportCJSWithNodeModuleKind verifies that auto-imports use require()
// syntax in CJS files when using node16/node20/nodenext module kinds with a
// package.json that has "type": "commonjs".
func TestAutoImportCJSWithNodeModuleKind(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"module": "node20",
"checkJs": true,
"noEmit": true
}
}
// @Filename: /package.json
{ "type": "commonjs" }
// @Filename: /lib.js
module.exports = { LIB_VERSION: 1 };
// @Filename: /main.js
module.exports.foo = 0;
LIB_VERSION/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyImportFixAtPosition(t, []string{
`const { LIB_VERSION } = require("./lib");
module.exports.foo = 0;
LIB_VERSION`,
}, nil /*preferences*/)
}
// TestAutoImportCJSWithNodeModuleKindEmptyFile verifies that auto-imports use
// require() syntax even in empty CJS files when using node module kinds.
func TestAutoImportCJSWithNodeModuleKindEmptyFile(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"module": "node20",
"checkJs": true,
"noEmit": true
}
}
// @Filename: /package.json
{ "type": "commonjs" }
// @Filename: /lib.js
module.exports = { LIB_VERSION: 1 };
// @Filename: /main.js
LIB_VERSION/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyImportFixAtPosition(t, []string{
`const { LIB_VERSION } = require("./lib");
LIB_VERSION`,
}, nil /*preferences*/)
}
// TestAutoImportCJSWithModuleDetectionForce verifies that auto-imports use
// require() syntax in JS files with CJS syntax when moduleDetection is "force",
// even with --module preserve where GetImpliedNodeFormatForEmit won't help.
func TestAutoImportCJSWithModuleDetectionForce(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"module": "preserve",
"moduleDetection": "force",
"checkJs": true,
"noEmit": true
}
}
// @Filename: /lib.js
export const LIB_VERSION = 1;
// @Filename: /main.js
const path = require("path");
LIB_VERSION/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyImportFixAtPosition(t, []string{
`const path = require("path");
const { LIB_VERSION } = require("./lib");
LIB_VERSION`,
}, nil /*preferences*/)
}

View File

@@ -0,0 +1,122 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportCompletion1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: a.ts
export const someVar = 10;
// @Filename: b.ts
export const anotherVar = 10;
// @Filename: c.ts
import {someVar} from "./a.ts";
someVar;
a/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"someVar", "anotherVar"},
},
})
f.BaselineAutoImportsCompletions(t, []string{""})
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
// completion autoimport preferences off; this tests if fourslash server communication correctly registers changes in user preferences
IncludeCompletionsForModuleExports: core.TSFalse,
IncludeCompletionsForImportStatements: core.TSFalse,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"anotherVar"},
},
})
}
func TestAutoImportCompletion2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: a.ts
export const someVar = 10;
export const anotherVar = 10;
// @Filename: c.ts
import {someVar} from "./a.ts";
someVar;
a/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"someVar", "anotherVar"},
},
})
f.BaselineAutoImportsCompletions(t, []string{""})
}
func TestAutoImportCompletion3(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: a.ts
export const aa = "asdf";
export const someVar = 10;
export const bb = 10;
// @Filename: c.ts
import { aa, someVar } from "./a.ts";
someVar;
b/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"bb"},
},
})
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,37 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
util "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportCompletionsForArbitraryNonIdentifierExports(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @module: esnext
// @Filename: /a.ts
const foo = 0;
export { foo as "foo-bar" };
export const fooBar = 1;
// @Filename: /b.ts
foo/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"foo-bar"},
Includes: []fourslash.CompletionsExpectedItem{"fooBar"},
},
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &util.DefaultCommitCharacters,
EditRange: util.Ignored,
},
})
}

View File

@@ -0,0 +1,54 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportCrossProjectNodeModules verifies that when multiple projects share
// a node_modules directory, auto-imports for a project only show packages that are
// either listed in that project's package.json dependencies OR directly imported
// by that project's files.
//
// Scenario:
// - Two separate projects (project-a and project-b) share a root node_modules
// - pkg-listed is in both package.json dependencies
// - pkg-unlisted is NOT in any package.json, but project-a imports it directly
// - When requesting completions in project-b, pkg-unlisted should NOT appear
// because project-b doesn't list it and doesn't import it directly.
func TestAutoImportCrossProjectNodeModules(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /node_modules/pkg-listed/package.json
{ "name": "pkg-listed", "version": "1.0.0" }
// @Filename: /node_modules/pkg-listed/index.d.ts
export declare const pkg_listed_value: number;
// @Filename: /node_modules/pkg-unlisted/package.json
{ "name": "pkg-unlisted", "version": "1.0.0" }
// @Filename: /node_modules/pkg-unlisted/index.d.ts
export declare const pkg_unlisted_value: string;
// @Filename: /project-a/tsconfig.json
{ "compilerOptions": { "module": "commonjs", "strict": true } }
// @Filename: /project-a/package.json
{ "name": "project-a", "dependencies": { "pkg-listed": "*" } }
// @Filename: /project-a/index.ts
import { pkg_unlisted_value } from "pkg-unlisted";
console.log(pkg_unlisted_value);
// @Filename: /project-b/tsconfig.json
{ "compilerOptions": { "module": "commonjs", "strict": true } }
// @Filename: /project-b/package.json
{ "name": "project-b", "dependencies": { "pkg-listed": "*" } }
// @Filename: /project-b/index.ts
pkg_/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Open project-a's file first - this establishes that project-a imports pkg-unlisted
f.GoToFile(t, "/project-a/index.ts")
// Now go to project-b and baseline auto-imports
f.GoToMarker(t, "")
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,56 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportCssModule(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @Filename: /tsconfig.json
{ "compilerOptions": { "module": "nodenext", "moduleResolution": "nodenext" } }
// @Filename: /package.json
{ "type": "module" }
// @Filename: /augmentations.ts
export {};
declare module "./styles.css" {
export const myClass: string;
}
// @Filename: /index.ts
myClass/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Verify auto-import completions don't panic when importing from .css module augmentation
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "myClass",
Data: &lsproto.CompletionItemData{
AutoImport: &lsproto.AutoImportFix{
ModuleSpecifier: "./styles.css",
},
},
AdditionalTextEdits: fourslash.AnyTextEdits,
SortText: new(string(ls.SortTextAutoImportSuggestions)),
},
},
},
})
}

View File

@@ -0,0 +1,235 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportDefaultPascalCase(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @Filename: /src/components/ChargerHeader.tsx
export default function ChargerHeader() {
return null;
}
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}
func TestAutoImportDefaultPascalCaseAnonymous(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @Filename: /src/components/ChargerHeader.tsx
export default function() {
return null;
}
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}
func TestAutoImportDefaultPascalCaseCaseInsensitive(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @useCaseSensitiveFileNames: false
// @Filename: /src/components/ChargerHeader.tsx
export default function ChargerHeader() {
return null;
}
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}
func TestAutoImportDefaultPascalCaseAnonymousCaseInsensitive(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @useCaseSensitiveFileNames: false
// @Filename: /src/components/ChargerHeader.tsx
export default function() {
return null;
}
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}
func TestAutoImportDefaultPascalCaseReexportCaseInsensitive(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @useCaseSensitiveFileNames: false
// @Filename: /src/components/ChargerHeader.tsx
export default function() {
return null;
}
// @Filename: /src/components/index.ts
export { default } from "./ChargerHeader";
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}
func TestAutoImportDefaultPascalCaseAliasCaseInsensitive(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @module: esnext
// @moduleResolution: bundler
// @useCaseSensitiveFileNames: false
// @Filename: /src/components/ChargerHeader.tsx
function ChargerHeader() {
return null;
}
export default ChargerHeader;
// @Filename: /src/screens/SomeScreen.tsx
export function SomeScreen() {
return <ChargerHeader/*1*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
UserPreferences: &lsutil.UserPreferences{
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
},
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"ChargerHeader"},
},
})
f.BaselineAutoImportsCompletions(t, []string{"1"})
}

View File

@@ -0,0 +1,28 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportErrorMixedExportKinds(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: a.ts
export function foo(): number {
return 10
}
const bar = 20;
export { bar as foo };
// @Filename: b.ts
foo/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Verify we don't crash from the mixed exports
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,35 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportExportEqualsOfImportStar(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: commonjs
// @Filename: /node_modules/mdx/package.json
{ "name": "mdx", "version": "1.0.0", "types": "index.d.ts" }
// @Filename: /node_modules/mdx/index.d.ts
import * as mdx from './lib/index.js'
export = mdx
// @Filename: /node_modules/mdx/lib/index.d.ts
export * from './core.js'
export * from './compile.js'
// @Filename: /node_modules/mdx/lib/core.d.ts
export declare function core(): void
// @Filename: /node_modules/mdx/lib/compile.d.ts
export declare function compile(): void
// @Filename: /package.json
{ "dependencies": { "mdx": "*" } }
// @Filename: /index.ts
mdx/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,54 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportFileExcludePatterns(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: foo.ts
export const mySymbol = 1;
// @Filename: ignoreme.ts
export const ignoredSymbol = 2;
// @Filename: bar.ts
mySym/*1*/
ignoredSym/*2*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.Configure(t, lsutil.UserPreferences{
AutoImportFileExcludePatterns: []string{"*ignoreme.ts"},
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
})
// Verify that mySymbol is included, but ignoredSymbol is excluded from completions
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"mySymbol"},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"ignoredSymbol"},
},
})
// Baseline the auto-imports
f.BaselineAutoImportsCompletions(t, []string{"1", "2"})
}

View File

@@ -0,0 +1,30 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportModuleAugmentation(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
export interface Foo {
x: number;
}
// @Filename: /b.ts
export {};
declare module "./a" {
export const Foo: any;
}
// @Filename: /c.ts
Foo/**/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportNewLine(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
export function readFileSync() {}
// @Filename: /b.ts
import {} from "./other1";
import {} from "./other2";
readFileSync/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.BaselineAutoImportsCompletions(t, []string{""})
}
func TestAutoImportNewLineWithHeaderComment(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
export function readFileSync() {}
// @Filename: /b.ts
/* file header comment */
import {} from "./other1";
import {} from "./other2";
readFileSync/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,57 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportNodeBuiltinNodenext is a regression test for
// https://github.com/microsoft/typescript-go/issues/2555, where auto-imports
// for Node.js built-in modules (e.g. "fs") were not appearing when using
// module: nodenext and types: ["node"].
func TestAutoImportNodeBuiltinNodenext(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{ "compilerOptions": { "module": "nodenext", "types": ["node"] } }
// @Filename: /package.json
{ "type": "module" }
// @Filename: /node_modules/@types/node/package.json
{ "name": "@types/node", "version": "22.0.0" }
// @Filename: /node_modules/@types/node/index.d.ts
declare module "fs" {
export function existsSync(path: string): boolean;
export function mkdirSync(path: string, options?: { recursive?: boolean }): void;
}
declare module "node:fs" { export * from "fs"; }
// @Filename: /index.ts
existsSync/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "existsSync",
Data: &lsproto.CompletionItemData{
AutoImport: &lsproto.AutoImportFix{
ModuleSpecifier: "node:fs",
},
},
AdditionalTextEdits: fourslash.AnyTextEdits,
SortText: new(string(ls.SortTextAutoImportSuggestions)),
},
},
},
})
}

View File

@@ -0,0 +1,61 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportPackageJsonImportsHashSlashNodenext(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{
"compilerOptions": {
"module": "nodenext",
"rootDir": "./",
"outDir": "build"
}
}
// @Filename: /package.json
{
"imports": {
"#/*": {
"types": "./src/*",
"default": "./src/*"
}
}
}
// @Filename: /src/domain/entities/entity.ts
export const entity = 1;
// @Filename: /src/features/deep/consumer.ts
entit/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.BaselineAutoImportsCompletions(t, []string{""})
}
func TestAutoImportPackageJsonImportsHashSlashNode16(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /tsconfig.json
{
"compilerOptions": {
"module": "node16"
}
}
// @Filename: /package.json
{
"imports": {
"#/*": "./src/*"
}
}
// @Filename: /src/domain/entities/entity.ts
export const entity = 1;
// @Filename: /src/consumer.ts
entit/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,33 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportQuoteDetection(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: esnext
// @Filename: /a.ts
export const foo = 0;
// @Filename: /b.ts
import {} from 'node:path';
fo/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyApplyCodeActionFromCompletion(t, new(""), &fourslash.ApplyCodeActionFromCompletionOptions{
Name: "foo",
Source: "./a",
Description: "Add import from \"./a\"",
NewFileContent: new(`import {} from 'node:path';
import { foo } from './a';
fo`),
})
}

View File

@@ -0,0 +1,49 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportReexportOfCrossPackageAugmentation verifies no crash when auto-importing
// from a package that re-exports from another package that is also augmented.
func TestAutoImportReexportOfCrossPackageAugmentation(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /node_modules/vitest/package.json
{ "name": "vitest", "version": "1.0.0", "types": "index.d.ts" }
// @Filename: /node_modules/vitest/index.d.ts
export { AugmentedInterface, uniqueFunction } from "@vitest/expect";
// @Filename: /node_modules/vitest/augmentation.d.ts
export {};
declare module "@vitest/expect" {
interface AugmentedInterface {
bar: string;
}
function uniqueFunction(): void;
}
// @Filename: /node_modules/@vitest/expect/package.json
{ "name": "@vitest/expect", "version": "1.0.0", "types": "index.d.ts" }
// @Filename: /node_modules/@vitest/expect/index.d.ts
export interface AugmentedInterface {
baz: number;
}
// @Filename: /tsconfig.json
{ "compilerOptions": { "module": "commonjs", "strict": true } }
// @Filename: /package.json
{ "name": "test", "dependencies": { "vitest": "*" } }
// @Filename: /index.ts
uniqueFunction/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
prefs := lsutil.NewDefaultUserPreferences()
prefs.AutoImportEntrypointDirectorySearch = core.TSTrue
f.Configure(t, prefs)
f.GoToMarker(t, "")
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,54 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportSpecifierExcludeRegexes(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: foo.ts
export const mySymbol = 1;
// @Filename: ignoreme.ts
export const ignoredSymbol = 2;
// @Filename: bar.ts
mySym/*1*/
ignoredSym/*2*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.Configure(t, lsutil.UserPreferences{
AutoImportSpecifierExcludeRegexes: []string{".*ignoreme.*"},
IncludeCompletionsForModuleExports: core.TSTrue,
IncludeCompletionsForImportStatements: core.TSTrue,
})
// Verify that mySymbol is included, but ignoredSymbol is excluded from completions
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"mySymbol"},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"ignoredSymbol"},
},
})
// Baseline the auto-imports
f.BaselineAutoImportsCompletions(t, []string{"1", "2"})
}

View File

@@ -0,0 +1,88 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportSymlinkedMonorepoGranularUpdate verifies that when a file in a symlinked
// project reference is edited, the auto-import index is updated efficiently via granular
// updates rather than rebuilding the entire node_modules bucket.
//
// Scenario:
// - project-a references project-b via project references (tsconfig)
// - project-b is symlinked into project-a's node_modules
// - Initially, project-b exports projectBValue
// - We get completions in project-a (builds the initial index)
// - We edit project-b to add a new export (newlyAddedFunction)
// - We get completions again in project-a
// - The new export should be available, proving the granular update worked
func TestAutoImportSymlinkedMonorepoGranularUpdate(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /packages/project-b/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"module": "commonjs",
"strict": true
},
"include": ["src"]
}
// @Filename: /packages/project-b/package.json
{
"name": "project-b",
"version": "1.0.0",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
}
// @Filename: /packages/project-b/src/index.ts
export const projectBValue: number = 42;
/*projectBEdit*/
// @Filename: /packages/project-b/dist/index.d.ts
export declare const projectBValue: number;
// @Filename: /packages/project-a/tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"references": [{ "path": "../project-b" }]
}
// @Filename: /packages/project-a/package.json
{ "name": "project-a", "dependencies": { "project-b": "*" } }
// @Filename: /packages/project-a/src/index.ts
import { projectBValue } from "project-b";
console.log(projectBValue);
newlyAdded/*projectACompletion*/
// @link: /packages/project-b -> /packages/project-a/node_modules/project-b`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Get initial completions in project-a - this builds the initial auto-import index.
// At this point, newlyAddedFunction doesn't exist yet in project-b.
f.GoToMarker(t, "projectACompletion")
f.BaselineAutoImportsCompletions(t, []string{"projectACompletion"})
// Now edit project-b's source file to add a new export.
// This should trigger a granular update when we request completions again.
f.GoToMarker(t, "projectBEdit")
f.Insert(t, "\nexport function newlyAddedFunction(): void {}")
// Go back to project-a and request completions again.
// The granular update should have picked up the new export from project-b.
f.GoToMarker(t, "projectACompletion")
f.BaselineAutoImportsCompletions(t, []string{"projectACompletion"})
}

View File

@@ -0,0 +1,73 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportSymlinkedMonorepoProjectReferencesNoPkgExports verifies deduplication
// when a monorepo package has both src and dist files, uses project references,
// but does NOT have package.json "exports" to limit what files are discovered.
//
// Scenario:
// - project-a references project-b via project references (tsconfig)
// - project-b is also symlinked into project-a's node_modules
// - project-b has both src/index.ts and dist/index.d.ts
// - package.json does NOT have "exports", so node_modules search finds BOTH src and dist
// - The program resolves imports to src files via project reference mapping
// - We should NOT see duplicate auto-imports (one from src, one from dist)
func TestAutoImportSymlinkedMonorepoProjectReferencesNoPkgExports(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /packages/project-b/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"module": "commonjs",
"strict": true
},
"include": ["src"]
}
// @Filename: /packages/project-b/package.json
{
"name": "project-b",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts"
}
// @Filename: /packages/project-b/src/index.ts
export const projectBValue: number = 42;
export function projectBFunction(): string { return "hello"; }
// @Filename: /packages/project-b/dist/index.d.ts
export declare const projectBValue: number;
export declare function projectBFunction(): string;
// @Filename: /packages/project-a/tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"references": [{ "path": "../project-b" }]
}
// @Filename: /packages/project-a/package.json
{ "name": "project-a", "dependencies": { "project-b": "*" } }
// @Filename: /packages/project-a/src/index.ts
import { projectBValue } from "project-b";
console.log(projectBValue);
projectBFunc/**/
// @link: /packages/project-b -> /packages/project-a/node_modules/project-b`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
// This should show projectBFunction once, not twice (not from both src and dist)
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,78 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportSymlinkedMonorepoProjectReferences verifies that when a monorepo package
// is symlinked into node_modules and has both src and dist files with project references,
// auto-imports don't show duplicates.
//
// Scenario:
// - project-a references project-b via project references (tsconfig)
// - project-b is also symlinked into project-a's node_modules
// - project-b has both src/index.ts and dist/index.d.ts
// - package.json "exports" points to dist files
// - The node_modules bucket finds dist/.d.ts files
// - The program resolves to src files via project reference mapping
// - We should NOT see duplicate auto-imports (one from src, one from dist)
func TestAutoImportSymlinkedMonorepoProjectReferences(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /packages/project-b/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"module": "commonjs",
"strict": true
},
"include": ["src"]
}
// @Filename: /packages/project-b/package.json
{
"name": "project-b",
"version": "1.0.0",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
}
// @Filename: /packages/project-b/src/index.ts
export const projectBValue: number = 42;
export function projectBFunction(): string { return "hello"; }
// @Filename: /packages/project-b/dist/index.d.ts
export declare const projectBValue: number;
export declare function projectBFunction(): string;
// @Filename: /packages/project-a/tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"references": [{ "path": "../project-b" }]
}
// @Filename: /packages/project-a/package.json
{ "name": "project-a", "dependencies": { "project-b": "*" } }
// @Filename: /packages/project-a/src/index.ts
import { projectBValue } from "project-b";
console.log(projectBValue);
projectBFunc/**/
// @link: /packages/project-b -> /packages/project-a/node_modules/project-b`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
// This should show projectBFunction once, not twice (not from both src and dist)
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,90 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportSymlinkedMonorepoReexport verifies deduplication when a monorepo
// package re-exports symbols from deeper files via `export *`.
//
// Scenario:
// - project-a references project-b via project references (tsconfig)
// - project-b is symlinked into project-a's node_modules
// - project-b has src/utils/foo.ts with the actual export
// - project-b has src/index.ts with `export * from './utils/foo'`
// - The Export's Path field points to src/utils/foo.ts (where symbol is defined)
// - This path must also go through realpath normalization for deduplication
// - We should NOT see duplicate auto-imports
func TestAutoImportSymlinkedMonorepoReexport(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /packages/project-b/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"module": "commonjs",
"strict": true
},
"include": ["src"]
}
// @Filename: /packages/project-b/package.json
{
"name": "project-b",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts"
}
// @Filename: /packages/project-b/src/utils/foo.ts
export function projectBFunction(): string { return "hello"; }
// @Filename: /packages/project-b/src/index.ts
export * from './utils/foo';
export const projectBValue: number = 42;
// @Filename: /packages/project-b/dist/utils/foo.d.ts
export declare function projectBFunction(): string;
// @Filename: /packages/project-b/dist/index.d.ts
export * from './utils/foo';
export declare const projectBValue: number;
// @Filename: /packages/project-a/tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"references": [{ "path": "../project-b" }]
}
// @Filename: /packages/project-a/package.json
{ "name": "project-a", "dependencies": { "project-b": "*" } }
// @Filename: /packages/project-a/src/index.ts
import { projectBValue } from "project-b";
console.log(projectBValue);
projectBFunction/**/
// @link: /packages/project-b -> /packages/project-a/node_modules/project-b`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
prefs := lsutil.NewDefaultUserPreferences()
prefs.AutoImportEntrypointDirectorySearch = core.TSTrue
f.Configure(t, prefs)
f.GoToMarker(t, "")
// This should show projectBFunction once via re-export and once via direct import, not duplicates
f.VerifyImportFixAtPosition(t, []string{
`import { projectBFunction, projectBValue } from "project-b";
console.log(projectBValue);
projectBFunction`,
`import { projectBValue } from "project-b";
import { projectBFunction } from "project-b/src/utils/foo";
console.log(projectBValue);
projectBFunction`,
}, nil /*preferences*/)
}

View File

@@ -0,0 +1,86 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
const TestAutoImportSymlinkedMonorepoSourceUpdateScenario = `
// @Filename: /home/src/workspaces/project/tsconfig.base.json
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"composite": true
}
}
// @Filename: /home/src/workspaces/project/packages/foo/package.json
{
"name": "@packages/foo",
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./dist/index.js"
}
}
}
// @Filename: /home/src/workspaces/project/packages/foo/tsconfig.json
{ "extends": "../../tsconfig.base.json" }
// @Filename: /home/src/workspaces/project/packages/foo/src/index.ts
/*fooEdit*/
// @Filename: /home/src/workspaces/project/packages/bar/package.json
{
"name": "@packages/bar",
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./dist/index.js"
}
},
"dependencies": {
"@packages/foo": "*"
}
}
// @Filename: /home/src/workspaces/project/packages/bar/tsconfig.json
{ "extends": "../../tsconfig.base.json" }
// @Filename: /home/src/workspaces/project/packages/bar/src/index.ts
/*fooCompletion*/
// @Filename: /home/src/workspaces/project/package.json
{ "workspaces": ["packages/*"], "type": "module" }
// @link: /home/src/workspaces/project/packages/bar -> /home/src/workspaces/project/node_modules/@packages/bar
// @link: /home/src/workspaces/project/packages/foo -> /home/src/workspaces/project/node_modules/@packages/foo
`
func TestAutoImportSymlinkedMonorepoSourceUpdate(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, TestAutoImportSymlinkedMonorepoSourceUpdateScenario)
defer done()
// Force auto import to build the cache (no exports yet).
f.GoToMarker(t, "fooCompletion")
f.BaselineAutoImportsCompletions(t, []string{"fooCompletion"})
// Add a new export to the symlinked source package.
f.GoToMarker(t, "fooEdit")
f.Insert(t, "\nexport function foo() {}")
// The new export should appear via granular cache update.
f.GoToMarker(t, "fooCompletion")
f.BaselineAutoImportsCompletions(t, []string{"fooCompletion"})
}

View File

@@ -0,0 +1,42 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// TestAutoImportSymlinkedMonorepo verifies that when a monorepo package is symlinked
// into node_modules and imported, auto-imports don't show duplicates.
//
// Scenario:
// - project-a imports "project-b" via a symlink in node_modules
// - project-b's source files are at /packages/project-b but symlinked to
// /packages/project-a/node_modules/project-b
// - The program contains project-b files via realpath, AND the symlink exists in node_modules
// - We should NOT see duplicate auto-imports for project-b exports
func TestAutoImportSymlinkedMonorepo(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /packages/project-b/package.json
{ "name": "project-b", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" }
// @Filename: /packages/project-b/index.d.ts
export declare const projectBValue: number;
export declare function projectBFunction(): string;
// @Filename: /packages/project-a/tsconfig.json
{ "compilerOptions": { "module": "commonjs", "strict": true } }
// @Filename: /packages/project-a/package.json
{ "name": "project-a", "dependencies": { "project-b": "*" } }
// @Filename: /packages/project-a/index.ts
import { projectBValue } from "project-b";
console.log(projectBValue);
projectBFunc/**/
// @link: /packages/project-b -> /packages/project-a/node_modules/project-b`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
// This should show projectBFunction once, not twice
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,117 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
const TestAutoImportTransitiveLeakScenario = `
// @Filename: /home/src/workspaces/project/tsconfig.base.json
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"composite": true
}
}
// @Filename: /home/src/workspaces/project/packages/foo/package.json
{
"name": "@packages/foo",
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./dist/index.js"
}
},
"imports": {
"#*": {
"types": "./src/*.ts",
"default": "./dist/*.js"
}
}
}
// @Filename: /home/src/workspaces/project/packages/foo/tsconfig.json
{ "extends": "../../tsconfig.base.json" }
// @Filename: /home/src/workspaces/project/packages/foo/src/internal/index.ts
export function fooInternal() {
console.log("foo");
}
// @Filename: /home/src/workspaces/project/packages/foo/src/index.ts
import { fooInternal } from "#internal/index"
export function foo() {
fooInternal();
}
// @Filename: /home/src/workspaces/project/packages/bar/package.json
{
"name": "@packages/bar",
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./dist/index.js"
}
},
"imports": {
"#*": {
"types": "./src/*.ts",
"default": "./dist/*.js"
}
},
"dependencies": {
"@packages/foo": "*"
}
}
// @Filename: /home/src/workspaces/project/packages/bar/tsconfig.json
{ "extends": "../../tsconfig.base.json" }
// @Filename: /home/src/workspaces/project/packages/bar/src/index.ts
import { foo } from "@packages/foo"
fo/*fooCompletion*/
// @Filename: /home/src/workspaces/project/package.json
{ "workspaces": ["packages/*"], "type": "module" }
// @link: /home/src/workspaces/project/packages/bar -> /home/src/workspaces/project/node_modules/@packages/bar
// @link: /home/src/workspaces/project/packages/foo -> /home/src/workspaces/project/node_modules/@packages/foo
`
func TestAutoImportTransitiveLeak(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, TestAutoImportTransitiveLeakScenario)
defer done()
f.VerifyCompletions(t, "fooCompletion", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "foo",
AdditionalTextEdits: fourslash.AnyTextEdits,
SortText: new(string(ls.SortTextLocationPriority)),
},
},
Excludes: []string{"fooInternal"},
},
})
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestAutoImportTypedefMissingName(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @allowJs: true
// @checkJs: true
// @Filename: /utils.js
/** @typedef {{ x: number }} */
export function doSomething() {}
// @Filename: /index.ts
doSomething/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.BaselineAutoImportsCompletions(t, []string{""})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicBackspace(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `export {};
interface Point {
x: number;
y: number;/*b*/
}
declare const p: Point;
p./*a*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"y"},
},
})
f.GoToMarker(t, "b")
f.Backspace(t, 10) // `y: number;`
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"y"},
},
})
}

View File

@@ -0,0 +1,28 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicClassElementKeywords(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `class C {
/*a*/
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
},
Items: &fourslash.CompletionsExpectedItems{
Exact: CompletionClassElementKeywords,
},
})
}

View File

@@ -0,0 +1,44 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicEdit(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `export {};
interface Point {
x: number;
y: number;
}
declare const p: Point;
p/*a*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "a")
f.Insert(t, ".")
f.GoToEOF(t)
f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "x",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
"y",
},
},
})
}

View File

@@ -0,0 +1,27 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicGlobalCompletions(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @lib: es5
/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: CompletionGlobals,
},
})
}

View File

@@ -0,0 +1,41 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicInterfaceMembers(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `export {};
interface Point {
x: number;
y: number;
}
declare const p: Point;
p./*a*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "x",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
"y",
},
},
})
}

View File

@@ -0,0 +1,124 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicJSDocCompletions(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @filename: file.js
// @allowJs: true
/**
* @/*1*/
*/
function foo(x) {
return x + 1;
}
/**
* /*2*/
*/
function bar(x, { y }) {
return x + y;
}
/**
* @param {number} x
* /*3*/
*/
function baz(x, { y }) {
return x + y;
}
/**
* @param {number} x
* @param {object} param1
* @param {n/*4*/} param1.y
*/
function baz(x, { y }) {
return x + y;
}
/**
* @/*5*/
*/
function baz(x = 0) {
return x * 2;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "link",
Kind: new(lsproto.CompletionItemKindKeyword),
Detail: new("link"),
},
"param",
"returns",
"param {*} x ",
},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"@param",
"@param {*} x ",
},
},
})
f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"@param",
"@param {object} param1 \n* @param {*} param1.y ",
},
},
})
f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"number",
},
},
})
f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"param {number} [x=0] ",
},
},
})
}

View File

@@ -0,0 +1,39 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicMultifileCompletions(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
export const foo = { bar: 'baz' };
// @Filename: /b.ts
import { foo } from './a';
const test = foo./*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
},
},
})
}

View File

@@ -0,0 +1,33 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicQuickInfo(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
/**
* Some var
*/
var someVar/*1*/ = 123;
/**
* Other var
* See {@link someVar}
*/
var otherVar/*2*/ = someVar;
class Foo/*3*/ {
#bar: string;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "1", "var someVar: number", "Some var")
f.VerifyQuickInfoAt(t, "2", "var otherVar: number", "Other var\nSee [someVar](file:///basicQuickInfo.ts#5,5-5,12)")
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestBasicReplaceLine(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `export {};
interface Point {
x: number;
y: number;
}
declare const p: Point;
p./*a*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{"y"},
},
})
f.ReplaceLine(t, 3, " z: number;") // `y: number;`
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Excludes: []string{"y"},
Includes: []fourslash.CompletionsExpectedItem{"z"},
},
})
}

View File

@@ -0,0 +1,21 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousClassNoCrash1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
class {
con/*1*/structor() {}
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,21 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousClassNoCrash2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
(class {
con/*1*/structor() {}
})`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,27 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousClassNoCrash3(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
import Bar from "./other";
function foo() {
new /*1*/Bar();
}
// @Filename: /other.ts
export default class {
constructor() {}
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,19 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousFunctionNoCrash1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
func/*1*/tion() {}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,19 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousFunctionNoCrash2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
(func/*1*/tion() {})`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyAnonymousFunctionNoCrash3(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
import bar from "./other";
function foo() {
/*1*/bar();
}
// @Filename: /other.ts
export default function() {}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyInPropDeclarationOfExportedDefaultClass1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /main.ts
export default class {
onSave = () => {
const values = [];
values./*m1*/push(1);
};
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "m1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,33 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyIncomingCallsNoCrashArrayPush(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `function splitNames(name: string) {
return (name || "").split(",").filter(Boolean);
}
async function trim(packageNames: string[]) {
const nameOrPkgs = packageNames.filter(Boolean);
const names = [];
for (const nameOrPkg of nameOrPkgs) {
try {
names./*push*/push(nameOrPkg);
} catch (error) {
}
}
return names;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "push")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyIncomingCallsObjectLiteralMethodInExpressionComputedProperty(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `const obj = {
[1 + 2]: {
method() {
return ""./*split*/split(",");
}
}
};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "split")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,26 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyIncomingCallsObjectLiteralMethodInIdentifierComputedProperty(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `const key = "x";
const obj = {
[key]: {
method() {
return ""./*split*/split(",");
}
}
};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "split")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyIncomingCallsObjectLiteralMethodInStringLiteralComputedProperty(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `const obj = {
["x"]: {
method() {
return ""./*split*/split(",");
}
}
};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "split")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,29 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCallHierarchyUnclosedTemplateExprNoCrash1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
// Regression test for a crash in prepareCallHierarchy caused by parser error
// recovery: when a template expression is truncated mid-call (e.g. `${format`
// without closing `)`), the parser misinterprets the `class` keyword in
// subsequent HTML template literals as a TypeScript class declaration.
// The resulting anonymous ClassDeclaration (no name, no `default` modifier)
// previously caused a "Expected call hierarchy declaration to have a reference
// node" assertion failure.
const content = "// @Filename: /main.ts\n" +
"function updateBadge() {\n" +
" const header = `<div class=\"sub\">${format`;\n" +
" const badge = `<div /*1*/class=\"badge\">`;\n" +
"}"
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.VerifyBaselineCallHierarchy(t)
}

View File

@@ -0,0 +1,52 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestChineseCharacterDisplayInHover(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
interface 中文界面 {
上居中: string;
下居中: string;
}
class 中文类 {
获取中文属性(): 中文界面 {
return {
上居中: "上居中",
下居中: "下居中"
};
}
}
let /*instanceHover*/实例 = new 中文类();
let 属性对象 = 实例./*methodHover*/获取中文属性();`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "instanceHover", "let 实例: 中文类", "")
f.VerifyQuickInfoAt(t, "methodHover", "(method) 中文类.获取中文属性(): 中文界面", "")
}
func TestChineseCharacterDisplayInUnionTypes(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// Test the original issue: Chinese characters in method parameters should display correctly
class TSLine {
setLengthTextPositionPreset(/*methodParam*/preset: "上居中" | "下居中" | "右居中" | "左居中"): void {}
}
let lines = new TSLine();
lines./*method*/setLengthTextPositionPreset;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Verify that the method displays Chinese characters correctly in hover (this was the original problem)
f.VerifyQuickInfoAt(t, "method", `(method) TSLine.setLengthTextPositionPreset(preset: "上居中" | "下居中" | "右居中" | "左居中"): void`, "")
}

View File

@@ -0,0 +1,27 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// https://github.com/microsoft/typescript-go/issues/3944
func TestCodeFixImportNonTextualSpecifierText(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = "// @Filename: /a.ts\n" +
"import type { A } from `./${myFolder}/${myFile}`;\n" +
"\n" +
"new A/**/()"
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyImportFixAtPosition(t, []string{
"import { A } from `./${myFolder}/${myFile}`;\n" +
"\n" +
"new A()",
}, nil /*preferences*/)
}

View File

@@ -0,0 +1,24 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeFixMissingTypeAnnotationOnExports_arrowParensParamOnly(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @isolatedDeclarations: true
// @declaration: true
export const func = /*a*/x/*b*/ => 0;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "a")
f.VerifyCodeFix(t, fourslash.VerifyCodeFixOptions{
Description: `Add annotation of type 'any'`,
NewFileContent: `export const func = (x: any) => 0;`,
ApplyChanges: true,
})
}

View File

@@ -0,0 +1,22 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeFixMissingTypeAnnotationOnExports_arrowParens(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @isolatedDeclarations: true
// @declaration: true
export const func = x => x.substring("foo");`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCodeFixAll(t, fourslash.VerifyCodeFixAllOptions{
FixID: "fixMissingTypeAnnotationOnExports",
NewFileContent: `export const func = (x: any): any => x.substring("foo");`,
})
}

View File

@@ -0,0 +1,38 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeFixMissingTypeAnnotationOnExports_expandoNoDuplicates(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @declaration: true
// @isolatedDeclarations: true
// @Filename: /foo.mts
export function foo(): void {
}
foo.blah = 123;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Verify that only one code fix action is returned, not three identical ones.
f.VerifyCodeFixAvailableExact(t, []string{
"Annotate types of properties expando function in a namespace",
})
f.VerifyCodeFix(t, fourslash.VerifyCodeFixOptions{
Description: "Annotate types of properties expando function in a namespace",
NewFileContent: `export function foo(): void {
}
export declare namespace foo {
export var blah: number;
}
foo.blah = 123;`,
})
}

View File

@@ -0,0 +1,26 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeFixMissingTypeAnnotationOnExports_jsxWhitespaceText(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @isolatedDeclarations: true
// @declaration: true
// @module: preserve
// @Filename: /test.tsx
export const /**/elem = <div>
<span />
</div>;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
f.VerifyCodeFixAvailable(t, nil)
}

View File

@@ -0,0 +1,75 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// Test that auto-imports for JSX tags don't crash when React is type-imported.
// When both the JSX namespace (React) and the component need to be imported,
// getSymbolNamesToImport returns multiple names and the type-only promotion
// path should handle this gracefully instead of panicking.
func TestCodeFixPromoteTypeOnlyImportJsxTag(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: preserve
// @verbatimModuleSyntax: true
// @jsx: react
// @Filename: /react.ts
const React: any = {};
export default React;
// @Filename: /bar.tsx
import type React from "./react";
<Foo/**/ />;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
// The fix should promote the type-only import of React to a regular import.
// The "Cannot find name 'Foo'" error does not produce an auto-import for
// React since it's already imported (as type-only, handled by promotion).
f.VerifyImportFixAtPosition(t, []string{
`import React from "./react";
<Foo />;`,
}, nil /*preferences*/)
}
// Test edge case where both the component name (Foo) and the JSX namespace (React)
// are type-only imported. Each diagnostic is matched to its symbol via the error
// message, so each produces only its own promotion fix (no duplicates).
func TestCodeFixPromoteTypeOnlyImportJsxTagBothTypeOnly(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: preserve
// @verbatimModuleSyntax: true
// @jsx: react
// @Filename: /react.ts
const React: any = {};
export default React;
// @Filename: /foo.ts
export function Foo() { return null; }
// @Filename: /bar.tsx
import type React from "./react";
import type { Foo } from "./foo";
<Foo/**/ />;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
// Both Foo and React are type-only imported. The error message string
// matching disambiguates which diagnostic is about which symbol, so each
// diagnostic produces only its own promotion fix (no duplicates).
f.VerifyImportFixAtPosition(t, []string{
`import type React from "./react";
import { Foo } from "./foo";
<Foo />;`,
`import React from "./react";
import type { Foo } from "./foo";
<Foo />;`,
}, nil /*preferences*/)
}

View File

@@ -0,0 +1,41 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// Test case for crash when promoting type-only import to value import
// when existing type imports precede the new value import
// https://github.com/microsoft/typescript-go/issues/2559
func TestCodeFixPromoteTypeOnlyOrderingCrash(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: node18
// @verbatimModuleSyntax: true
// @Filename: /bar.ts
export interface AAA {}
export class BBB {}
// @Filename: /foo.ts
import type {
AAA,
BBB,
} from "./bar";
let x: AAA = new BBB()`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToFile(t, "/foo.ts")
f.VerifyImportFixAtPosition(t, []string{
`import {
BBB,
type AAA,
} from "./bar";
let x: AAA = new BBB()`,
}, nil /*preferences*/)
}

View File

@@ -0,0 +1,57 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensFunctionExpressions01(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @filename: anonymousFunctionExpressions.ts
export let anonFn1 = function () {};
export const anonFn2 = function () {};
let anonFn3 = function () {};
const anonFn4 = function () {};
// @filename: arrowFunctions.ts
export let arrowFn1 = () => {};
export const arrowFn2 = () => {};
let arrowFn3 = () => {};
const arrowFn4 = () => {};
// @filename: namedFunctions.ts
export let namedFn1 = function namedFn1() {
namedFn1();
}
namedFn1();
export const namedFn2 = function namedFn2() {
namedFn2();
}
namedFn2();
let namedFn3 = function namedFn3() {};
const namedFn4 = function namedFn4() {};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ReferencesCodeLensEnabled: core.TSTrue,
ReferencesCodeLensShowOnAllFunctions: core.TSTrue,
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue,
ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue,
},
})
}

View File

@@ -0,0 +1,54 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensFunctionsAndConstants01(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @module: preserve
// @filename: ./exports.ts
let callCount = 0;
export function foo(n: number): void {
callCount++;
if (n > 0) {
foo(n - 1);
}
else {
console.log("function was called " + callCount + " times");
}
}
foo(5);
export const bar = 123;
// @filename: ./importer.ts
import { foo, bar } from "./exports";
foo(5);
console.log(bar);
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ReferencesCodeLensEnabled: core.TSTrue,
ReferencesCodeLensShowOnAllFunctions: core.TSTrue,
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue,
ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue,
},
})
}

View File

@@ -0,0 +1,63 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensInterface01(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @module: preserve
// @filename: ./pointable.ts
export interface Pointable {
getX(): number;
getY(): number;
}
// @filename: ./classPointable.ts
import { Pointable } from "./pointable";
class Point implements Pointable {
getX(): number {
return 0;
}
getY(): number {
return 0;
}
}
// @filename: ./objectPointable.ts
import { Pointable } from "./pointable";
let x = 0;
let y = 0;
const p: Pointable = {
getX(): number {
return x;
},
getY(): number {
return y;
},
};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ReferencesCodeLensEnabled: core.TSTrue,
ReferencesCodeLensShowOnAllFunctions: core.TSTrue,
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue,
ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue,
},
})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensOverloads01(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
export function foo(x: number): number;
export function foo(x: string): string;
export function foo(x: string | number): string | number {
return x;
}
foo(1);
foo("hello");
// This one isn't expected to match any overload,
// but is really just here to test how it affects how code lens.
foo(Math.random() ? 1 : "hello");
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ReferencesCodeLensEnabled: core.TSTrue,
ReferencesCodeLensShowOnAllFunctions: core.TSTrue,
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue,
ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue,
},
})
}

View File

@@ -0,0 +1,47 @@
package fourslash_test
import (
"fmt"
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensReferencesShowOnAllClassMethods(t *testing.T) {
t.Parallel()
containingTestName := t.Name()
for _, value := range []core.Tristate{core.TSTrue, core.TSFalse} {
t.Run(fmt.Sprintf("%s=%v", containingTestName, value.IsTrue()), func(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
export abstract class ABC {
abstract methodA(): void;
methodB(): void {}
#methodC(): void {}
protected methodD(): void {}
private methodE(): void {}
protected abstract methodG(): void;
public methodH(): void {}
static methodStaticA(): void {}
protected static methodStaticB(): void {}
private static methodStaticC(): void {}
static #methodStaticD(): void {}
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnAllClassMethods: value,
},
})
})
}
}

View File

@@ -0,0 +1,42 @@
package fourslash_test
import (
"fmt"
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensReferencesShowOnAllFunctions(t *testing.T) {
t.Parallel()
containingTestName := t.Name()
for _, value := range []core.Tristate{core.TSTrue, core.TSFalse} {
t.Run(fmt.Sprintf("%s=%v", containingTestName, value.IsTrue()), func(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
export function f1(): void {}
function f2(): void {}
export const f3 = () => {};
const f4 = () => {};
const f5 = function() {};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ReferencesCodeLensEnabled: core.TSTrue,
ReferencesCodeLensShowOnAllFunctions: value,
},
})
})
}
}

View File

@@ -0,0 +1,56 @@
package fourslash_test
import (
"fmt"
"testing"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCodeLensReferencesShowOnInterfaceMethods(t *testing.T) {
t.Parallel()
containingTestName := t.Name()
for _, value := range []core.Tristate{core.TSTrue, core.TSFalse} {
t.Run(fmt.Sprintf("%s=%v", containingTestName, value.IsTrue()), func(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
export interface I {
methodA(): void;
}
export interface I {
methodB(): void;
}
interface J extends I {
methodB(): void;
methodC(): void;
}
class C implements J {
methodA(): void {}
methodB(): void {}
methodC(): void {}
}
class AbstractC implements J {
abstract methodA(): void;
methodB(): void {}
abstract methodC(): void;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{
CodeLens: lsutil.CodeLensUserPreferences{
ImplementationsCodeLensEnabled: core.TSTrue,
ImplementationsCodeLensShowOnInterfaceMethods: value,
},
})
})
}
}

View File

@@ -0,0 +1,32 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionAfterCallExpression(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `let x = someCall() /**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"satisfies",
"as",
},
},
})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionAfterExtendsL10nInJs(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @allowJs: true
// @checkJs: true
// @Filename: /interfaces.d.ts
export interface IL10n {}
// @Filename: /genericl10n.js
/** @typedef {import("./interfaces").IL10n} IL10n */
class L10n {
constructor(options) {
this.options = options;
}
}
/**
* @implements {IL10n}
*/
class GenericL10n extends L10n/*1*/ {
constructor(lang) {
super({ lang });
}
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
f.GetCompletions(t, nil /*userPreferences*/)
}

View File

@@ -0,0 +1,52 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionAfterTrailingAtInJSDoc1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @allowJs: true
// @Filename: /atTagPosition.js
/**
* @/*1*/
*/
function foo(x) {}
// @Filename: /atAfterExistingParam.js
/**
* @param {string} x ok
* @/*2*/
*/
function bar(x, y) {}
// @Filename: /atMidLine.js
/**
* some text @/*3*/
*/
function baz(y) {}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, []string{"1", "2", "3"}, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "param",
Kind: new(lsproto.CompletionItemKindKeyword),
},
},
},
})
}

View File

@@ -0,0 +1,38 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionClassMemberAfterJSDocWithInvalidJSDocTagInTheComment1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `export class NeedsPrefix {
private _prefixes: {
add: Record<string, any>;
browsers: {selected: string[]};
};
constructor(browsers: string[]) {
}
/** Checks whether an @-rule needs to be prefixed. */
/**/atRule(identifier: string): boolean {
return true;
}
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,46 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestClassMembersAfterConstAssertionInitializer(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
interface A {
a: number
def: string
}
class B implements A {
a = 1 as const
/**/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: append([]fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "def",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
}, CompletionClassElementKeywords...),
},
})
}

View File

@@ -0,0 +1,40 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionColonToken(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @filename: /a.ts
:/*a*/
// @filename: /b.ts
function b(class: /*b*/) {}
// @filename: /c.ts
function c(enum: /*c*/) {}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
for _, marker := range f.Ranges() {
f.VerifyCompletions(t, marker, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: CompletionGlobals,
},
})
}
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionDetailSignature(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
/*a*/
function foo(x: string): string;
function foo(x: number): number;
function foo(x: any): any {
return x;
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "foo",
Kind: new(lsproto.CompletionItemKindFunction),
SortText: new(string(ls.SortTextLocationPriority)),
Detail: new("function foo(x: string): string\nfunction foo(x: number): number"),
},
},
},
})
}

View File

@@ -0,0 +1,236 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionFilterText1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
class Foo1 {
#bar: number;
constructor(bar: number) {
this.[|b|]/*1*/
}
}
class Foo5 {
#bar: number;
constructor(bar: number) {
this./*5*/
}
}
class Foo2 {
#bar: number;
constructor(bar: number) {
this.[|#b|]/*2*/
}
}
class Foo6 {
#bar: number;
constructor(bar: number) {
this.[|#|]/*6*/
}
}
class Foo3 {
#bar: number;
constructor(bar: number) {
[|b|]/*3*/
}
}
class Foo7 {
#bar: number;
constructor(bar: number) {
/*7*/
}
}
class Foo4 {
#bar: number;
constructor(bar: number) {
[|#b|]/*4*/
}
}
class Foo8 {
#bar: number;
constructor(bar: number) {
[|#|]/*8*/
}
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: &fourslash.EditRange{
Insert: f.Ranges()[0],
Replace: f.Ranges()[0],
},
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
FilterText: new("bar"),
},
},
},
})
f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
FilterText: new("bar"),
},
},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: &fourslash.EditRange{
Insert: f.Ranges()[1],
Replace: f.Ranges()[1],
},
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
},
},
})
f.VerifyCompletions(t, "6", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: &fourslash.EditRange{
Insert: f.Ranges()[2],
Replace: f.Ranges()[2],
},
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
},
},
})
f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextSuggestedClassMembers)),
FilterText: new("bar"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
InsertReplaceEdit: &lsproto.InsertReplaceEdit{
NewText: "this.#bar",
Insert: f.Ranges()[3].LSRange,
Replace: f.Ranges()[3].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "7", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextSuggestedClassMembers)),
FilterText: new("bar"),
InsertText: new("this.#bar"),
},
},
},
})
f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextSuggestedClassMembers)),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
InsertReplaceEdit: &lsproto.InsertReplaceEdit{
NewText: "this.#bar",
Insert: f.Ranges()[4].LSRange,
Replace: f.Ranges()[4].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "8", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "#bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextSuggestedClassMembers)),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
InsertReplaceEdit: &lsproto.InsertReplaceEdit{
NewText: "this.#bar",
Insert: f.Ranges()[5].LSRange,
Replace: f.Ranges()[5].LSRange,
},
},
},
},
},
})
}

View File

@@ -0,0 +1,65 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionFilterText2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @strict: true
declare const foo1: { bar: string } | undefined;
if (true) {
foo1[|.|]/*1*/
}
else {
foo1?./*2*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("?.bar"),
FilterText: new(".bar"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "?.bar",
Range: f.Ranges()[0].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "bar",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
},
},
},
})
}

View File

@@ -0,0 +1,153 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionFilterText3(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @strict: true
declare const foo1: { b: number; "a bc": string; };
if (true) {
foo1[|.|]/*1*/
}
else {
foo1[|.a|]/*2*/
}
declare const foo2: { b: number; "a bc": string; } | undefined;
if (true) {
foo2[|.|]/*3*/
} else if (false) {
foo2[|.a|]/*4*/
} else {
foo2[|?.|]/*5*/
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a bc",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("[\"a bc\"]"),
FilterText: new(".a bc"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "[\"a bc\"]",
Range: f.Ranges()[0].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a bc",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("[\"a bc\"]"),
FilterText: new(".a bc"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "[\"a bc\"]",
Range: f.Ranges()[1].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a bc",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("?.[\"a bc\"]"),
FilterText: new(".a bc"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "?.[\"a bc\"]",
Range: f.Ranges()[2].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a bc",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("?.[\"a bc\"]"),
FilterText: new(".a bc"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "?.[\"a bc\"]",
Range: f.Ranges()[3].LSRange,
},
},
},
},
},
})
f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a bc",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("?.[\"a bc\"]"),
FilterText: new("?.a bc"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "?.[\"a bc\"]",
Range: f.Ranges()[4].LSRange,
},
},
},
},
},
})
}

View File

@@ -0,0 +1,44 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionFilterText4(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `declare const x: [number, number];
x[|.|]/**/;
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "0",
Kind: new(lsproto.CompletionItemKindField),
SortText: new(string(ls.SortTextLocationPriority)),
InsertText: new("[0]"),
FilterText: new(".0"),
TextEdit: &lsproto.TextEditOrInsertReplaceEdit{
TextEdit: &lsproto.TextEdit{
NewText: "[0]",
Range: f.Ranges()[0].LSRange,
},
},
},
},
},
})
}

View File

@@ -0,0 +1,31 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// !!! can delete, there are similar tests that haven't been ported yet.
func TestCompletionImportAttributes(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @target: esnext
// @module: esnext
// @filename: main.ts
import yadda1 from "yadda" with {/*attr*/}
import yadda2 from "yadda" with {attr/*attrEnd1*/: true}
import yadda3 from "yadda" with {attr: /*attrValue*/}
// @filename: yadda
export default {};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToEachMarker(t, nil, func(marker *fourslash.Marker, index int) {
f.VerifyCompletions(t, marker, nil)
})
}

View File

@@ -0,0 +1,55 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
// Test that requesting completions after a keyword in an import statement
// doesn't crash with a nil pointer dereference.
// Reproduces issue: import super/*cursor*/
// Before the fix, this would panic with: runtime error: invalid memory address or nil pointer dereference
func TestCompletionImportKeywordNoCrash(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
emptyCommitChars := []string{}
// Test with "super" keyword
{
const content = `import super/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &emptyCommitChars,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"type",
},
},
})
done()
}
// Test with "this" keyword
{
const content = `import this/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &emptyCommitChars,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"type",
},
},
})
done()
}
}

View File

@@ -0,0 +1,30 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionInArrayLiteralAfterInvalidToken1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `const pairs: Record<string, [string, string]> = {
a: ["x",:/*m1*/]
};
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "m1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,31 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionInJSDocPropertyWithLinkNoCrash1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @allowJs: true
// @filename: /file.js
export function foo() {}
/**
* @typedef MyType
* @property {number} [timeout] - The /*1*/timeout; defaults to {@linkcode DEFAULT}
*/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{CommitCharacters: &[]string{".", ",", ";"}},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,33 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionJSDocNoCrash2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @allowJs: true
// @filename: file.js
/**
* @param {Object} obj
* @param {string} obj.first The first property
* @param {string} obj.second The second property
* @param {string} obj.third The {@link foo} third property
*/
/*1*/function foo(obj) {}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// The assertion here is simply "does not crash/panic".
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{CommitCharacters: &[]string{".", ",", ";"}},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,32 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionJSDocNoCrash(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @allowJs: true
// @filename: file.js
class ErrorMap {
/**
* @type {string}
*//*1*/
errorMap;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// The assertion here is simply "does not crash/panic".
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{CommitCharacters: &[]string{".", ",", ";"}},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,26 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionJsxNoCrash(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @filename: file.tsx
<Foo/>/*1*/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// The assertion here is simply "does not crash/panic".
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{CommitCharacters: &[]string{".", ",", ";"}},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,47 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionListAlreadyImportedNamespaceExportAlias(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @module: node18
// @Filename: /values.ts
export const A = 1;
export const B = 2;
// @Filename: /namespace.ts
import * as Group from "./values.js";
type Group = (typeof Group)[keyof typeof Group];
export { Group };
// @Filename: /index.ts
import { Group } from "./namespace.js";
console.log(Grou/**/);`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
result := f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{Label: "Group"},
},
},
})
result.AndHasNoCodeAction(t, &fourslash.CompletionsExpectedCodeAction{
Name: "Group",
Source: "./namespace.js",
})
}

View File

@@ -0,0 +1,28 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionListDefaultTypeArgumentPositionTypeOnly(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @lib: es5
const foo = "foo";
function test1<T = /*1*/>() {}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: CompletionGlobalTypes,
},
})
}

View File

@@ -0,0 +1,79 @@
package fourslash_test
import (
"strings"
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionListInUnclosedTypeArguments(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `let x = 10;
type Type = void;
declare function f<T>(): void;
declare function f2<T, U>(): void;
f</*1a*/T/*2a*/y/*3a*/
f</*1b*/T/*2b*/y/*3b*/;
f</*1c*/T/*2c*/y/*3c*/>
f</*1d*/T/*2d*/y/*3d*/>
f</*1e*/T/*2e*/y/*3e*/>();
f2</*1k*/T/*2k*/y/*3k*/,
f2</*1l*/T/*2l*/y/*3l*/,{| "newId": true |}T{| "newId": true |}y{| "newId": true |}
f2</*1m*/T/*2m*/y/*3m*/,{| "newId": true |}T{| "newId": true |}y{| "newId": true |};
f2</*1n*/T/*2n*/y/*3n*/,{| "newId": false |}T{| "newId": false |}y{| "newId": false |}>
f2</*1o*/T/*2o*/y/*3o*/,{| "newId": false |}T{| "newId": false |}y{| "newId": false |}>
f2</*1p*/T/*2p*/y/*3p*/,{| "newId": true, "typeOnly": true |}T{| "newId": true, "typeOnly": true |}y{| "newId": true, "typeOnly": true |}>();
f2<typeof /*1uValueOnly*/x, {| "newId": true |}T{| "newId": true |}y{| "newId": true |}
f2</*1x*/T/*2x*/y/*3x*/, () =>/*4x*/T/*5x*/y/*6x*/
f2<() =>/*1y*/T/*2y*/y/*3y*/, () =>/*4y*/T/*5y*/y/*6y*/
f2<any, () =>/*1z*/T/*2z*/y/*3z*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToEachMarker(t, nil, func(marker *fourslash.Marker, index int) {
markerName := marker.Name
valueOnly := markerName != nil && strings.HasSuffix(*markerName, "ValueOnly")
commitCharacters := &DefaultCommitCharacters
if marker.Data != nil {
newId := marker.Data["newId"]
typeOnly := marker.Data["typeOnly"]
if newId != nil && newId.(bool) && !(typeOnly != nil && typeOnly.(bool)) {
commitCharacters = &[]string{".", ";"}
}
}
var includes []fourslash.CompletionsExpectedItem
var excludes []string
if valueOnly {
includes = []fourslash.CompletionsExpectedItem{
"x",
}
excludes = []string{
"Type",
}
} else {
includes = []fourslash.CompletionsExpectedItem{
"Type",
}
excludes = []string{
"x",
}
}
f.VerifyCompletions(t, marker, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: commitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: includes,
Excludes: excludes,
},
})
})
}

View File

@@ -0,0 +1,45 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionResolveAfterEdit(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @filename: /index.ts
interface Point {
x: number;
y: number;
}
declare const p: Point;
/*a*/
// @filename: /foo.ts
/*b*/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Step 1: Get completions at the marker.
f.GoToMarker(t, "a")
completions := f.GetCompletions(t, nil /*userPreferences*/)
if completions == nil || len(completions.Items) == 0 {
t.Fatal("Expected completions but got none")
}
firstItem := completions.Items[0]
// Step 2: Make a file change (insert a comment after marker).
f.GoToMarker(t, "b")
f.Insert(t, "1")
// Step 3: Resolve the first completion item from the original list.
resolved := f.ResolveCompletionItem(t, firstItem)
if resolved == nil {
t.Fatal("Expected resolved completion item but got nil")
}
}

View File

@@ -0,0 +1,36 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionResolveKeyword(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `class C {
/*a*/
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "a", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "abstract",
Kind: new(lsproto.CompletionItemKindKeyword),
SortText: new(string(ls.SortTextGlobalsOrKeywords)),
Detail: new("abstract"),
},
},
},
})
}

View File

@@ -0,0 +1,37 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionWithUnterminatedJSDocEndingWithAt1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @allowJs: true
// @Filename: /atOnNewLineAtEOF.js
function foo(x) {}
/**
* @/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "param",
Kind: new(lsproto.CompletionItemKindKeyword),
},
},
},
})
}

View File

@@ -0,0 +1,36 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionWithUnterminatedJSDocEndingWithAt2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @allowJs: true
// @Filename: /atInTextAtEOF.js
function foo(x) {}
/** some text @/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "param",
Kind: new(lsproto.CompletionItemKindKeyword),
},
},
},
})
}

View File

@@ -0,0 +1,33 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsAtTopLevelImportAssignmentNoCrash1(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @filename: /a.ts
import x =/*1*/
class Foo {}
// @filename: /b.ts
import x = /*2*/
class Foo {}
// @filename: /c.ts
import x =/*3*/
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, []string{"1", "2", "3"}, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/ls"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsDeprecatedTags(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `const o = {
/** @deprecated */
a: 1,
b: 2,
c: 3,
}
o./**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "a",
Kind: new(lsproto.CompletionItemKindField),
Tags: &[]lsproto.CompletionItemTag{lsproto.CompletionItemTagDeprecated},
SortText: new(string(ls.DeprecateSortText(ls.SortTextLocationPriority))),
},
},
},
})
}

View File

@@ -0,0 +1,58 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsForContextualConstraintTypeInJsDoc(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @allowJs: true
// @filename: a.ts
export interface Blah<T extends { a: "hello" | "world" }> {
}
// @filename: b.js
/** @import * as a from "./a" */
/** @type {a.Blah<{ a: /*1*/ }>} */
let x;
// @filename: c.js
/** @import * as a from "./a" */
/** @type {a.Blah<{ a: /*2*/ }>} */
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// These examples both would panic in retrieving the symbols
// of property signature nodes within JSDoc types.
// In both cases, we'd have a JSDoc property signature that has no symbol.
//
// The two cases differ in whether or not there is a variable declaration
// following the `@type` comment. These are important to test differently
// because of how JSDoc re-parsing would construct nodes in the tree.
//
// Getting the symbol of the reparsed node is a sufficient fix for marker 1.
// However, that would not fix the case at marker 2 because
// there is no variable to attach the `@type` annotation, so the node basically
// doesn't exist for subsequent passes like the binder.
f.VerifyCompletions(t, f.Markers(), &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{CommitCharacters: &[]string{".", ",", ";"}},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
`"hello"`,
`"world"`,
},
},
})
}

View File

@@ -0,0 +1,43 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
fourslashUtil "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsOnImportIdentifierWithFromOnNextLine(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `import something/*1*/
from`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: fourslashUtil.Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}
func TestCompletionsOnImportTypeWithFromOnNextLine(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `import type/*1*/
from`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: fourslashUtil.Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,35 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsFromUntitledFile(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
// Test that completions work in untitled files without crashing.
// Regression test for https://github.com/microsoft/typescript-go/issues/2550
const content = `// @filename: /home/src/project/utils.ts
export function helper() {}
// @filename: ^/untitled/ts-nul-authority/Untitled-1.ts
/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
// Request completions - this should not crash
f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
// We don't care about the exact completions, just that it doesn't crash
Includes: nil,
},
})
}

View File

@@ -0,0 +1,64 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsInJsxTagDifferentSpreadElementTypes(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @Filename: /completionsWithDifferentSpreadTypes.tsx
// @strict: true
// A reasonable type to spread.
export function ComponentObjectX(props: { x: string }) {
return <SomeComponent {...props} /*objectX*//>;
}
// A questionable but valid type to spread.
export function ComponentObjectXOrY(props: { x: string } | { y: string }) {
return <SomeComponent {...props} /*objectXOrY*//>;
}
// A very unexpected type to spread (a union containing a primitive).
export function ComponentNumberOrObjectX(props: number | { x: string }) {
return <SomeComponent {...props} /*numberOrObjectX*//>;
}
// Very unexpected, but still structured (union) types.
// 'boolean' is 'true | false' and an optional 'null' is really 'null | undefined'.
export function ComponentBoolean(props: boolean) {
return <SomeComponent {...props} /*boolean*//>;
}
export function ComponentOptionalNull(props?: null) {
return <SomeComponent {...props} /*optNull*//>;
}
// Primitive types (non-structured).
export function ComponentAny(props: any) {
return <SomeComponent {...props} /*any*//>;
}
export function ComponentUnknown(props: unknown) {
return <SomeComponent {...props} /*unknown*//>;
}
export function ComponentNever(props: never) {
return <SomeComponent {...props} /*never*//>;
}
export function ComponentUndefined(props: undefined) {
return <SomeComponent {...props} /*undefined*//>;
}
export function ComponentNumber(props: number) {
return <SomeComponent {...props} /*number*//>;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToEachMarker(t, nil, func(marker *fourslash.Marker, index int) {
f.VerifyCompletions(t, marker, nil)
})
}

View File

@@ -0,0 +1,124 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsInJsxTag(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: preserve
// @Filename: /a.tsx
declare namespace JSX {
interface Element {}
interface IntrinsicElements {
div: {
/** Doc */
foo: string
/** Label docs */
"aria-label": string
}
}
}
class Foo {
render() {
<div /*1*/ ></div>;
<div /*2*/ />
}
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, []string{"1", "2"}, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "aria-label",
Kind: new(lsproto.CompletionItemKindField),
Detail: new("(property) \"aria-label\": string"),
Documentation: &lsproto.StringOrMarkupContent{
MarkupContent: &lsproto.MarkupContent{
Kind: lsproto.MarkupKindMarkdown,
Value: "Label docs",
},
},
},
&lsproto.CompletionItem{
Label: "foo",
Kind: new(lsproto.CompletionItemKindField),
Detail: new("(property) foo: string"),
Documentation: &lsproto.StringOrMarkupContent{
MarkupContent: &lsproto.MarkupContent{
Kind: lsproto.MarkupKindMarkdown,
Value: "Doc",
},
},
},
},
},
})
}
func TestCompletionsInJsxNamespacedIntrinsicTag(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: react
// @Filename: /a.tsx
declare const React: any;
declare namespace JSX {
interface Element {}
interface IntrinsicElements {
/** Element docs */
"foo:bar": {
/** Foo docs */
foo: boolean
/** Bar docs */
bar: string
}
}
}
<foo:bar /*1*/ />
<foo:bar /*2*/></foo:bar>`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, []string{"1", "2"}, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{
Exact: []fourslash.CompletionsExpectedItem{
&lsproto.CompletionItem{
Label: "bar",
Kind: new(lsproto.CompletionItemKindField),
Detail: new("(property) bar: string"),
Documentation: &lsproto.StringOrMarkupContent{
MarkupContent: &lsproto.MarkupContent{
Kind: lsproto.MarkupKindMarkdown,
Value: "Bar docs",
},
},
},
&lsproto.CompletionItem{
Label: "foo",
Kind: new(lsproto.CompletionItemKindField),
Detail: new("(property) foo: boolean"),
Documentation: &lsproto.StringOrMarkupContent{
MarkupContent: &lsproto.MarkupContent{
Kind: lsproto.MarkupKindMarkdown,
Value: "Foo docs",
},
},
},
},
},
})
}

View File

@@ -0,0 +1,44 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsJSDocSignature(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @noLib: true
// @checkJs: true
// @allowJs: true
// @filename: index.js
/**
* @type {{
* (input: string):/*1*/ X|Y/*2*/
* }}
*/
let x;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{".", ",", ";"},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{".", ",", ";"},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,35 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsJSDocTrivia(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @noLib: true
/**
* @type {{
* 'string-property': boolean;
*/*$*/ identifierProperty: boolean;
* }}
*/
var someVariable;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "$")
f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{".", ",", ";"},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

View File

@@ -0,0 +1,55 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsPathUnknownExtension(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @filename: src/some-file.ruhroh
/* This is just a test file that needs to exist. */
// @filename: package.json
{
"imports": {
"#/*": "./src/*"
}
}
// @filename: src/globals.d.ts
declare module "*.ruhroh";
// @filename: src/a.mts
import "#//*$*/"
// @filename: tsconfig.json
{
"compilerOptions": {
"module": "preserve",
"moduleResolution": "bundler",
"rootDir": "src"
},
"include": ["src"]
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "$", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: Ignored,
},
Items: &fourslash.CompletionsExpectedItems{
Includes: []fourslash.CompletionsExpectedItem{
"some-file.ruhroh",
},
},
})
}

View File

@@ -0,0 +1,34 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsSelfDeclaring2(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @lib: es5
function f1<T>(x: T) {}
f1({ [|abc|]/*1*/ });`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
IsIncomplete: false,
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &[]string{},
EditRange: &fourslash.EditRange{
Insert: f.Ranges()[0],
Replace: f.Ranges()[0],
},
},
Items: &fourslash.CompletionsExpectedItems{
Exact: CompletionGlobalsPlus([]fourslash.CompletionsExpectedItem{
"f1",
}, false /*noLib*/),
},
})
}

View File

@@ -0,0 +1,25 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
. "github.com/microsoft/typescript-go/internal/fourslash/tests/util"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestCompletionsUnterminatedLiteral(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @noLib: true
function foo(a"/*1*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
CommitCharacters: &DefaultCommitCharacters,
},
Items: &fourslash.CompletionsExpectedItems{},
})
}

Some files were not shown because too many files have changed in this diff Show More