vendor tsgo
This commit is contained in:
4715
tools/tsgo/internal/fourslash/_scripts/convertFourslash.mts
Normal file
4715
tools/tsgo/internal/fourslash/_scripts/convertFourslash.mts
Normal file
File diff suppressed because it is too large
Load Diff
1
tools/tsgo/internal/fourslash/_scripts/crashingTests.txt
Normal file
1
tools/tsgo/internal/fourslash/_scripts/crashingTests.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
459
tools/tsgo/internal/fourslash/_scripts/failingTests.txt
Normal file
459
tools/tsgo/internal/fourslash/_scripts/failingTests.txt
Normal file
@@ -0,0 +1,459 @@
|
||||
TestAliasMergingWithNamespace
|
||||
TestAllowLateBoundSymbolsOverwriteEarlyBoundSymbols
|
||||
TestAmbientShorthandGotoDefinition
|
||||
TestArgumentsAreAvailableAfterEditsAtEndOfFunction
|
||||
TestAugmentedTypesClass1
|
||||
TestAutoImportAllowImportingTsExtensionsPackageJsonImports1
|
||||
TestAutoImportCompletionAmbientMergedModule1
|
||||
TestAutoImportCompletionExportListAugmentation1
|
||||
TestAutoImportCompletionExportListAugmentation2
|
||||
TestAutoImportCompletionExportListAugmentation3
|
||||
TestAutoImportCompletionExportListAugmentation4
|
||||
TestAutoImportCrossProject_symlinks_stripSrc
|
||||
TestAutoImportCrossProject_symlinks_toDist
|
||||
TestAutoImportFileExcludePatterns10
|
||||
TestAutoImportFileExcludePatterns11
|
||||
TestAutoImportFileExcludePatterns3
|
||||
TestAutoImportFileExcludePatterns5
|
||||
TestAutoImportFileExcludePatterns6
|
||||
TestAutoImportFileExcludePatterns9
|
||||
TestAutoImportJsDocImport1
|
||||
TestAutoImportModuleNone2
|
||||
TestAutoImportNodeModuleSymlinkRenamed
|
||||
TestAutoImportNodeNextJSRequire
|
||||
TestAutoImportPackageJsonImportsCaseSensitivity
|
||||
TestAutoImportPackageRootPath
|
||||
TestAutoImportPathsNodeModules
|
||||
TestAutoImportProvider_exportMap2
|
||||
TestAutoImportProvider_exportMap9
|
||||
TestAutoImportProvider_globalTypingsCache
|
||||
TestAutoImportProvider9
|
||||
TestAutoImportRelativePathToMonorepoPackage
|
||||
TestAutoImportSortCaseSensitivity1
|
||||
TestAutoImportTypeImport4
|
||||
TestAutoImportTypeOnlyPreferred3
|
||||
TestAutoImportVerbatimTypeOnly1
|
||||
TestCloduleTypeOf1
|
||||
TestCodeCompletionEscaping
|
||||
TestCodeFixAddParameterNames1
|
||||
TestCodeFixAddParameterNames2
|
||||
TestCodeFixAddParameterNames3
|
||||
TestCodeFixClassExtendAbstractSomePropertiesPresent
|
||||
TestCodeFixClassImplementInterfaceNoTruncation
|
||||
TestCodeFixClassSuperMustPrecedeThisAccess
|
||||
TestCodeFixCorrectQualifiedNameToIndexedAccessType01
|
||||
TestCodeFixInferFromCallInAssignment
|
||||
TestCodeFixInferFromExpressionStatement
|
||||
TestCodeFixInferFromFunctionThisUsageObjectProperty
|
||||
TestCodeFixInferFromFunctionThisUsageObjectPropertyParameter
|
||||
TestCodeFixInferFromFunctionThisUsageObjectPropertyShorthand
|
||||
TestCodeFixInferFromFunctionThisUsageObjectPropertyShorthandParameter
|
||||
TestCodeFixInferFromFunctionUsage
|
||||
TestCodeFixInferFromPrimitiveUsage
|
||||
TestCodeFixInferFromUsageCall
|
||||
TestCodeFixInferFromUsageMember
|
||||
TestCodeFixInferFromUsageMember2
|
||||
TestCodeFixInferFromUsageMember3
|
||||
TestCodefixInferFromUsageNullish
|
||||
TestCodeFixInferFromUsageOptionalParam
|
||||
TestCodeFixInferFromUsageOptionalParam2
|
||||
TestCodeFixInferFromUsageRestParam
|
||||
TestCodeFixInferFromUsageRestParam2
|
||||
TestCodeFixInferFromUsageRestParam3
|
||||
TestCodeFixInferFromUsageVariable3JS
|
||||
TestCodeFixMissingTypeAnnotationOnExports16
|
||||
TestCodeFixMissingTypeAnnotationOnExports23_heritage_formatting
|
||||
TestCodeFixMissingTypeAnnotationOnExports25_heritage_formatting_3
|
||||
TestCodeFixMissingTypeAnnotationOnExports28_long_types
|
||||
TestCodeFixSpelling4
|
||||
TestCodeFixSpelling5
|
||||
TestCodeFixSpellingCaseSensitive1
|
||||
TestCodeFixSpellingCaseSensitive2
|
||||
TestCodeFixSpellingCaseSensitive3
|
||||
TestCodeFixSpellingCaseWeight1
|
||||
TestCodeFixSpellingCaseWeight2
|
||||
TestCodeFixSpellingShortName1
|
||||
TestCodeFixTopLevelAwait_module_targetES2017CompilerOptionsInTsConfig
|
||||
TestCodeFixTopLevelForAwait_module_targetES2017CompilerOptionsInTsConfig
|
||||
TestCodeFixUndeclaredPropertyAccesses
|
||||
TestCodeFixUnusedIdentifier_suggestion
|
||||
TestCodeFixUnusedInterfaceInNamespace1
|
||||
TestCodeFixUnusedInterfaceInNamespace2
|
||||
TestCommentsEnumsFourslash
|
||||
TestCommentsExternalModulesFourslash
|
||||
TestCommentsImportDeclaration
|
||||
TestCommentsInheritanceFourslash
|
||||
TestCommentsInterfaceFourslash
|
||||
TestCommentsLinePreservation
|
||||
TestCommentsOverloadsFourslash
|
||||
TestCommentsVariables
|
||||
TestCompletionAfterQuestionDot
|
||||
TestCompletionAutoInsertQuestionDot
|
||||
TestCompletionCloneQuestionToken
|
||||
TestCompletionEntryClassMembersWithInferredFunctionReturnType1
|
||||
TestCompletionEntryForArgumentConstrainedToString
|
||||
TestCompletionEntryForArrayElementConstrainedToString
|
||||
TestCompletionEntryForArrayElementConstrainedToString2
|
||||
TestCompletionEntryForUnionProperty
|
||||
TestCompletionEntryForUnionProperty2
|
||||
TestCompletionForComputedStringProperties
|
||||
TestCompletionForMetaProperty
|
||||
TestCompletionForObjectProperty
|
||||
TestCompletionForStringLiteral
|
||||
TestCompletionForStringLiteral_quotePreference
|
||||
TestCompletionForStringLiteral_quotePreference1
|
||||
TestCompletionForStringLiteral_quotePreference2
|
||||
TestCompletionForStringLiteral_quotePreference3
|
||||
TestCompletionForStringLiteral_quotePreference4
|
||||
TestCompletionForStringLiteral_quotePreference5
|
||||
TestCompletionForStringLiteral_quotePreference6
|
||||
TestCompletionForStringLiteral_quotePreference7
|
||||
TestCompletionForStringLiteral_quotePreference8
|
||||
TestCompletionForStringLiteral4
|
||||
TestCompletionImportMeta
|
||||
TestCompletionImportMetaWithGlobalDeclaration
|
||||
TestCompletionImportModuleSpecifierEndingUnsupportedExtension
|
||||
TestCompletionInChecks1
|
||||
TestCompletionInFunctionLikeBody_includesPrimitiveTypes
|
||||
TestCompletionInUncheckedJSFile
|
||||
TestCompletionListBuilderLocations_VariableDeclarations
|
||||
TestCompletionListForDerivedType1
|
||||
TestCompletionListInArrowFunctionInUnclosedCallSite01
|
||||
TestCompletionListInNamedFunctionExpression
|
||||
TestCompletionListInNamedFunctionExpression1
|
||||
TestCompletionListInNamedFunctionExpressionWithShadowing
|
||||
TestCompletionListInScope
|
||||
TestCompletionListInScope_doesNotIncludeAugmentations
|
||||
TestCompletionListInTemplateLiteralParts1
|
||||
TestCompletionListInUnclosedCommaExpression01
|
||||
TestCompletionListInUnclosedCommaExpression02
|
||||
TestCompletionListInUnclosedFunction08
|
||||
TestCompletionListInUnclosedFunction09
|
||||
TestCompletionListInUnclosedTaggedTemplate01
|
||||
TestCompletionListInUnclosedTaggedTemplate02
|
||||
TestCompletionListInUnclosedTemplate01
|
||||
TestCompletionListInUnclosedTemplate02
|
||||
TestCompletionListInvalidMemberNames
|
||||
TestCompletionListInvalidMemberNames_escapeQuote
|
||||
TestCompletionListInvalidMemberNames_startWithSpace
|
||||
TestCompletionListInvalidMemberNames_withExistingIdentifier
|
||||
TestCompletionListInvalidMemberNames2
|
||||
TestCompletionListOnAliases
|
||||
TestCompletionListsStringLiteralTypeAsIndexedAccessTypeObject
|
||||
TestCompletionListStringParenthesizedExpression
|
||||
TestCompletionListStringParenthesizedType
|
||||
TestCompletionListWithoutVariableinitializer
|
||||
TestCompletionNoAutoInsertQuestionDotForThis
|
||||
TestCompletionNoAutoInsertQuestionDotForTypeParameter
|
||||
TestCompletionNoAutoInsertQuestionDotWithUserPreferencesOff
|
||||
TestCompletionOfAwaitPromise1
|
||||
TestCompletionOfAwaitPromise2
|
||||
TestCompletionOfAwaitPromise3
|
||||
TestCompletionOfAwaitPromise5
|
||||
TestCompletionOfAwaitPromise6
|
||||
TestCompletionOfAwaitPromise7
|
||||
TestCompletionOfInterfaceAndVar
|
||||
TestCompletionPreferredSuggestions1
|
||||
TestCompletionsBeforeRestArg1
|
||||
TestCompletionsClassMemberImportTypeNodeParameter1
|
||||
TestCompletionsClassMemberImportTypeNodeParameter2
|
||||
TestCompletionsClassMemberImportTypeNodeParameter3
|
||||
TestCompletionsClassMemberImportTypeNodeParameter4
|
||||
TestCompletionsElementAccessNumeric
|
||||
TestCompletionsExportImport
|
||||
TestCompletionsImport_default_anonymous
|
||||
TestCompletionsImport_details_withMisspelledName
|
||||
TestCompletionsImport_exportEquals_global
|
||||
TestCompletionsImport_filteredByInvalidPackageJson_direct
|
||||
TestCompletionsImport_filteredByPackageJson_direct
|
||||
TestCompletionsImport_filteredByPackageJson_nested
|
||||
TestCompletionsImport_filteredByPackageJson_peerDependencies
|
||||
TestCompletionsImport_filteredByPackageJson_typesImplicit
|
||||
TestCompletionsImport_filteredByPackageJson_typesOnly
|
||||
TestCompletionsImport_named_didNotExistBefore
|
||||
TestCompletionsImport_noSemicolons
|
||||
TestCompletionsImport_quoteStyle
|
||||
TestCompletionsImport_umdDefaultNoCrash1
|
||||
TestCompletionsImport_uriStyleNodeCoreModules2
|
||||
TestCompletionsImport_uriStyleNodeCoreModules3
|
||||
TestCompletionsImport_windowsPathsProjectRelative
|
||||
TestCompletionsImportOrExportSpecifier
|
||||
TestCompletionsInExport
|
||||
TestCompletionsInExport_moduleBlock
|
||||
TestCompletionsJSDocNoCrash1
|
||||
TestCompletionsJsdocTypeTagCast
|
||||
TestCompletionsJsxAttributeInitializer2
|
||||
TestCompletionsLiteralFromInferenceWithinInferredType3
|
||||
TestCompletionsLiterals
|
||||
TestCompletionsMergedDeclarations1
|
||||
TestCompletionsNewTarget
|
||||
TestCompletionsOptionalMethod
|
||||
TestCompletionsOverridingMethod1
|
||||
TestCompletionsOverridingMethod10
|
||||
TestCompletionsOverridingMethod11
|
||||
TestCompletionsOverridingMethod14
|
||||
TestCompletionsOverridingMethod17
|
||||
TestCompletionsOverridingMethod2
|
||||
TestCompletionsOverridingMethod3
|
||||
TestCompletionsOverridingMethod4
|
||||
TestCompletionsOverridingMethod9
|
||||
TestCompletionsOverridingMethodCrash1
|
||||
TestCompletionsOverridingProperties1
|
||||
TestCompletionsRecommended_namespace
|
||||
TestCompletionsRecommended_union
|
||||
TestCompletionsRedeclareModuleAsGlobal
|
||||
TestCompletionsStringsWithTriggerCharacter
|
||||
TestCompletionsSymbolMembers
|
||||
TestCompletionsTriggerCharacter
|
||||
TestCompletionsTuple
|
||||
TestCompletionsUniqueSymbol_import
|
||||
TestCompletionsUniqueSymbol1
|
||||
TestCompletionsWithDeprecatedTag10
|
||||
TestConstQuickInfoAndCompletionList
|
||||
TestContextuallyTypedFunctionExpressionGeneric1
|
||||
TestContextualTypingOfGenericCallSignatures2
|
||||
TestDocCommentTemplateClassDecl01
|
||||
TestDocCommentTemplateClassDeclMethods01
|
||||
TestDocCommentTemplateFunctionExpression
|
||||
TestDocCommentTemplateIndentation
|
||||
TestDocCommentTemplateJsSpecialPropertyAssignment
|
||||
TestDocCommentTemplatePrototypeMethod
|
||||
TestDocCommentTemplateWithMultipleJSDoc1
|
||||
TestDocCommentTemplateWithMultipleJSDoc3
|
||||
TestDocCommentTemplateWithMultipleJSDocAndParameters
|
||||
TestDoubleUnderscoreCompletions
|
||||
TestEditJsdocType
|
||||
TestErrorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl
|
||||
TestExportDefaultClass
|
||||
TestExportDefaultFunction
|
||||
TestExportEqualTypes
|
||||
TestFindAllRefs_importType_js1
|
||||
TestFindAllRefs_importType_js2
|
||||
TestFindAllRefs_importType_js3
|
||||
TestFormatDotAfterNumber
|
||||
TestFormatNoSpaceAfterTemplateHeadAndMiddle
|
||||
TestFormatSpaceAfterTemplateHeadAndMiddle
|
||||
TestFormattingObjectLiteralOpenCurlyNewlineTyping
|
||||
TestFormattingObjectLiteralOpenCurlySingleLine
|
||||
TestFormattingOnInvalidCodes
|
||||
TestFormattingOnObjectLiteral
|
||||
TestFormatV8Directive
|
||||
TestFunduleWithRecursiveReference
|
||||
TestGenericCombinators3
|
||||
TestGenericCombinatorWithConstraints1
|
||||
TestGenericFunctionWithGenericParams1
|
||||
TestGetJavaScriptCompletions10
|
||||
TestGetJavaScriptCompletions12
|
||||
TestGetJavaScriptCompletions13
|
||||
TestGetJavaScriptCompletions15
|
||||
TestGetJavaScriptCompletions20
|
||||
TestGetJavaScriptCompletions8
|
||||
TestGetJavaScriptCompletions9
|
||||
TestGetJavaScriptGlobalCompletions1
|
||||
TestGetJavaScriptQuickInfo1
|
||||
TestGetJavaScriptQuickInfo2
|
||||
TestGetJavaScriptQuickInfo3
|
||||
TestGetJavaScriptQuickInfo4
|
||||
TestGetJavaScriptQuickInfo5
|
||||
TestGetJavaScriptQuickInfo6
|
||||
TestGetJavaScriptQuickInfo7
|
||||
TestGetJavaScriptSyntacticDiagnostics24
|
||||
TestGetJSXOutliningSpans
|
||||
TestHoverOverComment
|
||||
TestImportCompletionsPackageJsonImportsPatternRootWildcard
|
||||
TestImportFixesGlobalTypingsCache
|
||||
TestImportMetaCompletionDetails
|
||||
TestImportNameCodeFix_externalNonRelative1
|
||||
TestImportNameCodeFix_jsx4
|
||||
TestImportNameCodeFix_jsx6
|
||||
TestImportNameCodeFix_noDestructureNonObjectLiteral
|
||||
TestImportNameCodeFix_order2
|
||||
TestImportNameCodeFix_preferBaseUrl
|
||||
TestImportNameCodeFix_reExportDefault
|
||||
TestImportNameCodeFix_require
|
||||
TestImportNameCodeFix_require_addToExisting
|
||||
TestImportNameCodeFix_require_importVsRequire_addToExistingWins
|
||||
TestImportNameCodeFix_symlink_own_package_2
|
||||
TestImportNameCodeFix_uriStyleNodeCoreModules2
|
||||
TestImportNameCodeFix_uriStyleNodeCoreModules3
|
||||
TestImportNameCodeFixDefaultExport4
|
||||
TestImportNameCodeFixNewImportBaseUrl0
|
||||
TestImportNameCodeFixNewImportBaseUrl1
|
||||
TestImportNameCodeFixNewImportBaseUrl2
|
||||
TestImportNameCodeFixNewImportFile2
|
||||
TestImportNameCodeFixNewImportTypeRoots1
|
||||
TestImportStatementCompletions_esModuleInterop2
|
||||
TestImportStatementCompletions_noSnippet
|
||||
TestImportStatementCompletions_pnpm1
|
||||
TestImportStatementCompletions_quotes
|
||||
TestImportStatementCompletions_semicolons
|
||||
TestImportSuggestionsCache_invalidPackageJson
|
||||
TestImportTypeCompletions1
|
||||
TestImportTypeCompletions3
|
||||
TestImportTypeCompletions4
|
||||
TestImportTypeCompletions6
|
||||
TestImportTypeCompletions7
|
||||
TestImportTypeCompletions8
|
||||
TestImportTypeCompletions9
|
||||
TestIndirectClassInstantiation
|
||||
TestJavascriptModules20
|
||||
TestJavascriptModules24
|
||||
TestJsDocAugments
|
||||
TestJsDocAugmentsAndExtends
|
||||
TestJsdocCallbackTag
|
||||
TestJsDocExtends
|
||||
TestJsDocFunctionSignatures10
|
||||
TestJsDocFunctionSignatures13
|
||||
TestJsDocFunctionSignatures7
|
||||
TestJsDocFunctionSignatures8
|
||||
TestJsDocGenerics2
|
||||
TestJsDocInheritDoc
|
||||
TestJsDocPropertyDescription1
|
||||
TestJsDocPropertyDescription11
|
||||
TestJsDocPropertyDescription4
|
||||
TestJsDocPropertyDescription6
|
||||
TestJsDocPropertyDescription7
|
||||
TestJsDocPropertyDescription9
|
||||
TestJsDocTagsWithHyphen
|
||||
TestJsdocTemplatePrototypeCompletions
|
||||
TestJsdocTypedefTag
|
||||
TestJsdocTypedefTagNamespace
|
||||
TestJsFileImportNoTypes2
|
||||
TestJsQuickInfoGenerallyAcceptableSize
|
||||
TestJsRequireQuickInfo
|
||||
TestJsxAttributeCompletionStyleAuto
|
||||
TestJsxAttributeCompletionStyleBraces
|
||||
TestJsxAttributeCompletionStyleDefault
|
||||
TestJsxAttributeCompletionStyleNone
|
||||
TestJsxAttributeCompletionStyleNoSnippet
|
||||
TestJsxAttributeSnippetCompletionAfterTypeArgs
|
||||
TestJsxAttributeSnippetCompletionClosed
|
||||
TestJsxAttributeSnippetCompletionUnclosed
|
||||
TestJsxWithTypeParametershasInstantiatedSignatureHelp
|
||||
TestLetQuickInfoAndCompletionList
|
||||
TestLocalFunction
|
||||
TestMemberListInReopenedEnum
|
||||
TestMemberListInWithBlock
|
||||
TestMemberListOfExportedClass
|
||||
TestMultiModuleFundule
|
||||
TestNgProxy1
|
||||
TestNgProxy4
|
||||
TestNoQuickInfoForLabel
|
||||
TestNoQuickInfoInWhitespace
|
||||
TestOverloadQuickInfo
|
||||
TestProtoVarVisibleWithOuterScopeUnderscoreProto
|
||||
TestQuickfixImplementInterfaceUnreachableTypeUsesRelativeImport
|
||||
TestQuickInfo_notInsideComment
|
||||
TestQuickinfo01
|
||||
TestQuickInfoBindingPatternInJsdocNoCrash1
|
||||
TestQuickInfoCloduleWithRecursiveReference
|
||||
TestQuickInfoContextuallyTypedSignatureOptionalParameterFromIntersection1
|
||||
TestQuickInfoContextualTyping
|
||||
TestQuickInfoDisplayPartsIife
|
||||
TestQuickInfoElementAccessDeclaration
|
||||
TestQuickInfoForConstTypeReference
|
||||
TestQuickInfoForContextuallyTypedArrowFunctionInSuperCall
|
||||
TestQuickInfoForGenericConstraints1
|
||||
TestQuickInfoForGenericTaggedTemplateExpression
|
||||
TestQuickInfoForGetterAndSetter
|
||||
TestQuickInfoForIndexerResultWithConstraint
|
||||
TestQuickInfoForTypeofParameter
|
||||
TestQuickInfoForTypeParameterInTypeAlias2
|
||||
TestQuickInfoForUMDModuleAlias
|
||||
TestQuickinfoForUnionProperty
|
||||
TestQuickInfoFromContextualUnionType2
|
||||
TestQuickInfoFromContextualUnionType3
|
||||
TestQuickInfoFunctionKeyword
|
||||
TestQuickInfoGenerics
|
||||
TestQuickInfoGetterSetter
|
||||
TestQuickInfoInInvalidIndexSignature
|
||||
TestQuickInfoInJsdocInTsFile1
|
||||
TestQuickInfoJSDocBackticks
|
||||
TestQuickInfoJsdocEnum
|
||||
TestQuickInfoJSDocFunctionNew
|
||||
TestQuickInfoJSDocFunctionThis
|
||||
TestQuickInfoJsDocGetterSetterNoCrash1
|
||||
TestQuickInfoJsdocTypedefMissingType
|
||||
TestQuickInfoJSExport
|
||||
TestQuickInfoMappedSpreadTypes
|
||||
TestQuickInfoMappedType
|
||||
TestQuickInfoMeaning
|
||||
TestQuickInfoModuleVariables
|
||||
TestQuickInfoNarrowedTypeOfAliasSymbol
|
||||
TestQuickInfoOnArgumentsInsideFunction
|
||||
TestQuickInfoOnCatchVariable
|
||||
TestQuickInfoOnClosingJsx
|
||||
TestQuickInfoOnElementAccessInWriteLocation4
|
||||
TestQuickInfoOnElementAccessInWriteLocation5
|
||||
TestQuickInfoOnExpandoLikePropertyWithSetterDeclarationJs1
|
||||
TestQuickInfoOnExpandoLikePropertyWithSetterDeclarationJs2
|
||||
TestQuickInfoOnGenericWithConstraints1
|
||||
TestQuickInfoOnInternalAliases
|
||||
TestQuickInfoOnMergedModule
|
||||
TestQuickInfoOnNarrowedTypeInModule
|
||||
TestQuickInfoOnObjectLiteralWithAccessors
|
||||
TestQuickInfoOnObjectLiteralWithOnlyGetter
|
||||
TestQuickInfoOnObjectLiteralWithOnlySetter
|
||||
TestQuickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase
|
||||
TestQuickInfoOnPropertyAccessInWriteLocation4
|
||||
TestQuickInfoOnPropertyAccessInWriteLocation5
|
||||
TestQuickInfoOnThis3
|
||||
TestQuickInfoOnUndefined
|
||||
TestQuickInfoOnVarInArrowExpression
|
||||
TestQuickInfoPrivateIdentifierInTypeReferenceNoCrash1
|
||||
TestQuickInfoSpecialPropertyAssignment
|
||||
TestQuickInfoTemplateTag
|
||||
TestQuickInfoTypeAliasDefinedInDifferentFile
|
||||
TestQuickInfoTypeError
|
||||
TestQuickInfoTypeOfThisInStatics
|
||||
TestQuickInfoTypeOnlyNamespaceAndClass
|
||||
TestQuickInfoUnionOfNamespaces
|
||||
TestQuickInfoUntypedModuleImport
|
||||
TestQuickinfoWrongComment
|
||||
TestRecursiveInternalModuleImport
|
||||
TestRegexDetection
|
||||
TestSelfReferencedExternalModule
|
||||
TestSignatureHelpCallExpressionJs
|
||||
TestStringCompletionsImportOrExportSpecifier
|
||||
TestStringCompletionsVsEscaping
|
||||
TestSuggestionOfUnusedVariableWithExternalModule
|
||||
TestSymbolCompletionLowerPriority
|
||||
TestSyntheticImportFromBabelGeneratedFile1
|
||||
TestSyntheticImportFromBabelGeneratedFile2
|
||||
TestThisPredicateFunctionQuickInfo01
|
||||
TestThisPredicateFunctionQuickInfo02
|
||||
TestTsxQuickInfo4
|
||||
TestTsxQuickInfo5
|
||||
TestTsxQuickInfo6
|
||||
TestTsxQuickInfo7
|
||||
TestUnusedClassInNamespace1
|
||||
TestUnusedClassInNamespace3
|
||||
TestUnusedClassInNamespace4
|
||||
TestUnusedClassInNamespaceWithTrivia1
|
||||
TestUnusedClassInNamespaceWithTrivia2
|
||||
TestUnusedConstantInFunction1
|
||||
TestUnusedEnumInFunction1
|
||||
TestUnusedEnumInNamespace1
|
||||
TestUnusedFunctionInNamespace1
|
||||
TestUnusedFunctionInNamespace2
|
||||
TestUnusedFunctionInNamespace3
|
||||
TestUnusedFunctionInNamespace4
|
||||
TestUnusedFunctionInNamespace5
|
||||
TestUnusedFunctionInNamespaceWithTrivia
|
||||
TestUnusedImports10FS
|
||||
TestUnusedImports11FS
|
||||
TestUnusedImports12FS
|
||||
TestUnusedImports13FS
|
||||
TestUnusedImports14FS
|
||||
TestUnusedImports1FS
|
||||
TestUnusedImports3FS
|
||||
TestUnusedImports4FS
|
||||
TestUnusedImports5FS
|
||||
TestUnusedImports6FS
|
||||
TestUnusedImports7FS
|
||||
TestUnusedImports8FS
|
||||
TestUnusedImports9FS
|
||||
TestUnusedLocalsinConstructorFS1
|
||||
TestUnusedLocalsinConstructorFS2
|
||||
TestUnusedLocalsInFunction1
|
||||
TestUnusedLocalsInFunction3
|
||||
83
tools/tsgo/internal/fourslash/_scripts/makeManual.mts
Normal file
83
tools/tsgo/internal/fourslash/_scripts/makeManual.mts
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env -S node --experimental-strip-types --no-warnings
|
||||
|
||||
// Usage: node --experimental-strip-types --no-warnings makeManual.mts <testName> [...testNames]
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const scriptsDir = import.meta.dirname;
|
||||
const manualTestsPath = path.join(scriptsDir, "manualTests.txt");
|
||||
const genDir = path.join(scriptsDir, "../", "tests", "gen");
|
||||
const manualDir = path.join(scriptsDir, "../", "tests", "manual");
|
||||
const submoduleDir = path.join(scriptsDir, "../../../", "_submodules", "TypeScript", "tests", "cases", "fourslash");
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length === 0) {
|
||||
console.error("Please provide the name of the generated test file.");
|
||||
process.exit(1);
|
||||
}
|
||||
const testNames = [];
|
||||
for (const arg of args) {
|
||||
const testName = arg;
|
||||
const testFileName = testName;
|
||||
const genTestFile = path.join(genDir, testFileName + "_test.go");
|
||||
const submoduleTestFile = path.join(submoduleDir, testFileName + ".ts");
|
||||
const submoduleServerTestFile = path.join(submoduleDir, "server", testFileName + ".ts");
|
||||
let testKind: "gen" | "submodule" | "submoduleServer" | undefined;
|
||||
if (fs.existsSync(genTestFile)) {
|
||||
testKind = "gen";
|
||||
}
|
||||
else if (fs.existsSync(submoduleTestFile)) {
|
||||
testKind = "submodule";
|
||||
}
|
||||
else if (fs.existsSync(submoduleServerTestFile)) {
|
||||
testKind = "submoduleServer";
|
||||
}
|
||||
|
||||
if (!testKind) {
|
||||
console.error(
|
||||
`Could not find test neither as '${genTestFile}', nor as '${submoduleTestFile}' or '${submoduleServerTestFile}'.` +
|
||||
`Make sure the test exists in the gen directory or in the submodule.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(manualDir)) {
|
||||
fs.mkdirSync(manualDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (testKind === "gen") {
|
||||
const manualTestFile = path.join(manualDir, path.basename(genTestFile));
|
||||
markAsManual(genTestFile, manualTestFile);
|
||||
}
|
||||
|
||||
testNames.push(testName);
|
||||
}
|
||||
|
||||
let manualTests: string[] = [];
|
||||
if (fs.existsSync(manualTestsPath)) {
|
||||
const content = fs.readFileSync(manualTestsPath, "utf-8");
|
||||
manualTests = content.split("\n").map(line => line.trim()).filter(line => line.length > 0);
|
||||
}
|
||||
|
||||
for (const testName of testNames) {
|
||||
if (!manualTests.includes(testName)) {
|
||||
manualTests.push(testName);
|
||||
}
|
||||
}
|
||||
manualTests.sort((a, b) => a.localeCompare(b, "en-US"));
|
||||
fs.writeFileSync(manualTestsPath, [...manualTests, ""].join("\n"), "utf-8");
|
||||
}
|
||||
|
||||
function markAsManual(genFilePath: string, manualFilePath: string) {
|
||||
const content = fs.readFileSync(genFilePath, "utf-8");
|
||||
const updatedContent = content
|
||||
.replace(/^\/\/ Code generated by convertFourslash; DO NOT EDIT\.\n\/\/ To modify this test, run .*\n\n/m, "")
|
||||
.replace(/^\s*fourslash\.SkipIfFailing\(t\)\s*$/m, "");
|
||||
fs.writeFileSync(manualFilePath, updatedContent, "utf-8");
|
||||
fs.rmSync(genFilePath);
|
||||
}
|
||||
|
||||
main();
|
||||
177
tools/tsgo/internal/fourslash/_scripts/manualTests.txt
Normal file
177
tools/tsgo/internal/fourslash/_scripts/manualTests.txt
Normal file
@@ -0,0 +1,177 @@
|
||||
augmentedTypesModule2
|
||||
autoCloseFragment
|
||||
autoCloseTag
|
||||
autoImportCrossProject_symlinks_toSrc
|
||||
autoImportNoPackageJson_commonjs
|
||||
autoImportNoPackageJson_nodenext
|
||||
autoImportPackageRootPathExtension
|
||||
autoImportPackageRootPathTypeModule
|
||||
autoImportProvider5
|
||||
autoImportSymlinkCaseSensitive
|
||||
codeFixMissingTypeAnnotationOnExports45-decorators
|
||||
codeFixMissingTypeAnnotationOnExports46-decorators-experimental
|
||||
completionForStringLiteral_details
|
||||
completionForStringLiteralExport
|
||||
completionForStringLiteralImport1
|
||||
completionForStringLiteralImport2
|
||||
completionForStringLiteralNonrelativeImport12
|
||||
completionForStringLiteralNonrelativeImport14
|
||||
completionForStringLiteralNonrelativeImport16
|
||||
completionForStringLiteralNonrelativeImport4
|
||||
completionForStringLiteralNonrelativeImport8
|
||||
completionForStringLiteralRelativeImport4
|
||||
completionForStringLiteralWithDynamicImport
|
||||
completionImportModuleSpecifierEndingDts
|
||||
completionImportModuleSpecifierEndingJs
|
||||
completionImportModuleSpecifierEndingJsx
|
||||
completionImportModuleSpecifierEndingTs
|
||||
completionImportModuleSpecifierEndingTsxPreserve
|
||||
completionImportModuleSpecifierEndingTsxReact
|
||||
completionListInClosedFunction05
|
||||
completionListInImportClause05
|
||||
completionListInTypeLiteralInTypeParameter21
|
||||
completionListWithLabel
|
||||
completionsAtIncompleteObjectLiteralProperty
|
||||
completionsImport_defaultAndNamedConflict
|
||||
completionsImport_defaultFalsePositive
|
||||
completionsImport_filteredByPackageJson_ambient
|
||||
completionsImport_reExportDefault
|
||||
completionsImport_reexportTransient
|
||||
completionsPaths_importType
|
||||
completionsPaths_kinds
|
||||
completionsPaths_pathMapping
|
||||
completionsPaths_pathMapping_nonTrailingWildcard1
|
||||
completionsPaths_pathMapping_parentDirectory
|
||||
completionsPathsJsonModule
|
||||
completionsPathsRelativeJsonModule
|
||||
completionsSelfDeclaring1
|
||||
completionsWithDeprecatedTag4
|
||||
completionsWithStringReplacementMode1
|
||||
docCommentTemplateNamespacesAndModules01
|
||||
duplicatePackageServices_fileChanges
|
||||
exhaustiveCaseCompletions1
|
||||
exhaustiveCaseCompletions2
|
||||
exhaustiveCaseCompletions3
|
||||
exhaustiveCaseCompletions4
|
||||
exhaustiveCaseCompletions5
|
||||
exhaustiveCaseCompletions6
|
||||
exhaustiveCaseCompletions7
|
||||
exhaustiveCaseCompletions8
|
||||
formatOnEnterInComment
|
||||
getEditsForFileRename_caseInsensitive
|
||||
getEditsForFileRename_directory_down
|
||||
getEditsForFileRename_directory_up
|
||||
getEditsForFileRename_jsExtension
|
||||
getEditsForFileRename_preferences
|
||||
getEditsForFileRename_preservePathEnding
|
||||
getEditsForFileRename_resolveJsonModule
|
||||
getEditsForFileRename_shortenRelativePaths
|
||||
getEditsForFileRename_subDir
|
||||
getEditsForFileRename_unaffectedNonRelativePath
|
||||
getOutliningSpans
|
||||
importNameCodeFix_typesVersions
|
||||
importNameCodeFix_uriStyleNodeCoreModules1
|
||||
importNameCodeFixDefaultExport5
|
||||
importNameCodeFixDefaultExport7
|
||||
importNameCodeFixJsEnding
|
||||
importNameCodeFixNewImportNodeModules1
|
||||
importNameCodeFixOptionalImport0
|
||||
incrementalParsingWithJsDoc
|
||||
isDefinitionAcrossGlobalProjects
|
||||
jsdocDeprecated_suggestion1
|
||||
jsdocDeprecated_suggestion2
|
||||
jsDocFunctionSignatures12
|
||||
jsDocFunctionSignatures2
|
||||
jsdocParameterNameCompletion
|
||||
linkedEditingJsxTag1
|
||||
linkedEditingJsxTag12
|
||||
linkedEditingJsxTag2
|
||||
linkedEditingJsxTag4
|
||||
linkedEditingJsxTag5
|
||||
linkedEditingJsxTag6
|
||||
linkedEditingJsxTag7
|
||||
linkedEditingJsxTag9
|
||||
navigateItemsLet
|
||||
navigateToImport
|
||||
navigateToSymbolIterator
|
||||
navigationBarFunctionPrototype
|
||||
navigationBarFunctionPrototype2
|
||||
navigationBarFunctionPrototype3
|
||||
navigationBarFunctionPrototype4
|
||||
navigationBarFunctionPrototypeBroken
|
||||
navigationBarFunctionPrototypeInterlaced
|
||||
navigationBarFunctionPrototypeNested
|
||||
navigationBarJsDoc
|
||||
navigationItemsExactMatch2
|
||||
navigationItemsInConstructorsExactMatch
|
||||
navigationItemsPrefixMatch2
|
||||
navigationItemsSpecialPropertyAssignment
|
||||
navto_emptyPattern
|
||||
navto_excludeLib1
|
||||
navto_excludeLib2
|
||||
navto_excludeLib3
|
||||
navto_excludeLib4
|
||||
navto_serverExcludeLib
|
||||
nodeModulesImportCompletions1
|
||||
organizeImportsPathsUnicode3
|
||||
organizeImportsUnicode3
|
||||
outliningForNonCompleteInterfaceDeclaration
|
||||
outliningHintSpansForFunction
|
||||
overloadOnConstCallSignature
|
||||
parserCorruptionAfterMapInClass
|
||||
pathCompletionsPackageJsonExportsBundlerNoNodeCondition
|
||||
pathCompletionsPackageJsonExportsCustomConditions
|
||||
pathCompletionsPackageJsonExportsWildcard1
|
||||
pathCompletionsPackageJsonExportsWildcard10
|
||||
pathCompletionsPackageJsonExportsWildcard11
|
||||
pathCompletionsPackageJsonExportsWildcard12
|
||||
pathCompletionsPackageJsonExportsWildcard2
|
||||
pathCompletionsPackageJsonExportsWildcard3
|
||||
pathCompletionsPackageJsonExportsWildcard4
|
||||
pathCompletionsPackageJsonExportsWildcard5
|
||||
pathCompletionsPackageJsonExportsWildcard6
|
||||
pathCompletionsPackageJsonExportsWildcard7
|
||||
pathCompletionsPackageJsonExportsWildcard8
|
||||
pathCompletionsPackageJsonExportsWildcard9
|
||||
pathCompletionsPackageJsonImportsBundlerNoNodeCondition
|
||||
pathCompletionsPackageJsonImportsCustomConditions
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard1
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard2
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard3
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard4
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard5
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard6
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard7
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard8
|
||||
pathCompletionsPackageJsonImportsSrcNoDistWildcard9
|
||||
pathCompletionsPackageJsonImportsWildcard1
|
||||
pathCompletionsPackageJsonImportsWildcard10
|
||||
pathCompletionsPackageJsonImportsWildcard11
|
||||
pathCompletionsPackageJsonImportsWildcard12
|
||||
pathCompletionsPackageJsonImportsWildcard2
|
||||
pathCompletionsPackageJsonImportsWildcard3
|
||||
pathCompletionsPackageJsonImportsWildcard4
|
||||
pathCompletionsPackageJsonImportsWildcard5
|
||||
pathCompletionsPackageJsonImportsWildcard6
|
||||
pathCompletionsPackageJsonImportsWildcard7
|
||||
pathCompletionsPackageJsonImportsWildcard8
|
||||
pathCompletionsPackageJsonImportsWildcard9
|
||||
pathCompletionsTypesVersionsWildcard3
|
||||
pathCompletionsTypesVersionsWildcard4
|
||||
pathCompletionsTypesVersionsWildcard5
|
||||
pathCompletionsTypesVersionsWildcard6
|
||||
quickInfoForOverloadOnConst1
|
||||
renameDefaultKeyword
|
||||
renameForDefaultExport01
|
||||
semanticClassificationClassExpression
|
||||
semanticModernClassificationFunctions
|
||||
semicolonFormattingInsideAComment
|
||||
semicolonFormattingInsideAStringLiteral
|
||||
signatureHelpImportStarFromExportEquals
|
||||
signatureHelpOnOverloadOnConst
|
||||
stringLiteralCompletionsInPositionTypedUsingRest
|
||||
tripleSlashRefPathCompletionAbsolutePaths
|
||||
tripleSlashRefPathCompletionHiddenFile
|
||||
tsconfigComputedPropertyError
|
||||
tsxCompletion12
|
||||
typeErrorAfterStringCompletionsInNestedCall
|
||||
10
tools/tsgo/internal/fourslash/_scripts/tsconfig.json
Normal file
10
tools/tsgo/internal/fourslash/_scripts/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"module": "nodenext",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
2571
tools/tsgo/internal/fourslash/_scripts/unparsedTests.txt
Normal file
2571
tools/tsgo/internal/fourslash/_scripts/unparsedTests.txt
Normal file
File diff suppressed because it is too large
Load Diff
141
tools/tsgo/internal/fourslash/_scripts/updateFailing.mts
Normal file
141
tools/tsgo/internal/fourslash/_scripts/updateFailing.mts
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env -S node --experimental-strip-types --no-warnings
|
||||
|
||||
// Usage: node --experimental-strip-types --no-warnings updateFailing.mts
|
||||
|
||||
import * as cp from "child_process";
|
||||
import * as fs from "fs";
|
||||
import path from "path";
|
||||
import * as readline from "readline";
|
||||
import which from "which";
|
||||
|
||||
const failingTestsPath = path.join(import.meta.dirname, "failingTests.txt");
|
||||
const crashingTestsPath = path.join(import.meta.dirname, "crashingTests.txt");
|
||||
|
||||
interface TestEvent {
|
||||
Time?: string;
|
||||
Action: string;
|
||||
Package?: string;
|
||||
Test?: string;
|
||||
Output?: string;
|
||||
Elapsed?: number;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const go = which.sync("go");
|
||||
|
||||
let testProcess: cp.ChildProcess;
|
||||
try {
|
||||
// Run tests with TSGO_FOURSLASH_IGNORE_FAILING=1 to run all tests including those in failingTests.txt
|
||||
testProcess = cp.spawn(go, ["test", "-json", "./internal/fourslash/tests/gen"], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
env: { ...process.env, TSGO_FOURSLASH_IGNORE_FAILING: "1" },
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error("Failed to spawn test process: " + error);
|
||||
}
|
||||
|
||||
if (!testProcess.stdout || !testProcess.stderr) {
|
||||
throw new Error("Test process stdout or stderr is null");
|
||||
}
|
||||
|
||||
const failingTests: string[] = [];
|
||||
const crashingTests: string[] = [];
|
||||
const testOutputs = new Map<string, string[]>();
|
||||
const allOutputs: string[] = [];
|
||||
let hadPanic = false;
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: testProcess.stdout,
|
||||
crlfDelay: Infinity,
|
||||
});
|
||||
|
||||
rl.on("line", line => {
|
||||
try {
|
||||
const event: TestEvent = JSON.parse(line);
|
||||
|
||||
// Collect output for each test
|
||||
if (event.Action === "output" && event.Output) {
|
||||
allOutputs.push(event.Output);
|
||||
if (event.Test) {
|
||||
if (!testOutputs.has(event.Test)) {
|
||||
testOutputs.set(event.Test, []);
|
||||
}
|
||||
testOutputs.get(event.Test)!.push(event.Output);
|
||||
}
|
||||
|
||||
// Check for panics
|
||||
if (/^panic/m.test(event.Output)) {
|
||||
hadPanic = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Process failed tests
|
||||
if (event.Action === "fail" && event.Test) {
|
||||
const outputs = testOutputs.get(event.Test) || [];
|
||||
|
||||
// Check if this is a crashing test (contains InternalError)
|
||||
const hasCrash = outputs.some(line => line.includes("InternalError"));
|
||||
if (hasCrash) {
|
||||
crashingTests.push(event.Test);
|
||||
}
|
||||
|
||||
// A test is only considered a baseline-only failure if ALL error messages
|
||||
// are baseline-related. Any non-baseline error message means it's a real failure.
|
||||
const baselineMessagePatterns = [
|
||||
/^\s*baseline\.go:\d+: the baseline file .* has changed\./,
|
||||
/^\s*baseline\.go:\d+: new baseline created at /,
|
||||
/^\s*baseline\.go:\d+: the baseline file .* does not exist in the TypeScript submodule/,
|
||||
/^\s*baseline\.go:\d+: the baseline file .* does not match the reference in the TypeScript submodule/,
|
||||
];
|
||||
|
||||
// Check each output line that looks like an error message
|
||||
// Error messages from Go tests typically contain ".go:" with a line number
|
||||
const errorLines = outputs.filter(line => /^\s*\w+\.go:\d+:/.test(line));
|
||||
|
||||
// If there are no error lines, it's a real failure.
|
||||
// If all error lines match baseline patterns, it's a baseline-only failure
|
||||
const isBaselineOnlyFailure = errorLines.length > 0 &&
|
||||
errorLines.every(line => baselineMessagePatterns.some(pattern => pattern.test(line)));
|
||||
|
||||
if (!isBaselineOnlyFailure) {
|
||||
failingTests.push(event.Test);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// Not JSON, possibly stderr or other output - ignore
|
||||
}
|
||||
});
|
||||
|
||||
testProcess.stderr.on("data", data => {
|
||||
// Check stderr for panics too
|
||||
const output = data.toString();
|
||||
allOutputs.push(output);
|
||||
if (/^panic/m.test(output)) {
|
||||
hadPanic = true;
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
testProcess.on("close", code => {
|
||||
if (hadPanic) {
|
||||
reject(new Error("Unrecovered panic detected in tests\n" + allOutputs.join("")));
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(failingTestsPath, failingTests.sort((a, b) => a.localeCompare(b, "en-US")).join("\n") + "\n", "utf-8");
|
||||
fs.writeFileSync(crashingTestsPath, crashingTests.sort((a, b) => a.localeCompare(b, "en-US")).join("\n") + "\n", "utf-8");
|
||||
resolve();
|
||||
});
|
||||
|
||||
testProcess.on("error", error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error("Error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
1182
tools/tsgo/internal/fourslash/baselineutil.go
Normal file
1182
tools/tsgo/internal/fourslash/baselineutil.go
Normal file
File diff suppressed because it is too large
Load Diff
5815
tools/tsgo/internal/fourslash/fourslash.go
Normal file
5815
tools/tsgo/internal/fourslash/fourslash.go
Normal file
File diff suppressed because it is too large
Load Diff
130
tools/tsgo/internal/fourslash/semantictokens.go
Normal file
130
tools/tsgo/internal/fourslash/semantictokens.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package fourslash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ls/lsconv"
|
||||
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||
)
|
||||
|
||||
type SemanticToken struct {
|
||||
Type string
|
||||
Text string
|
||||
}
|
||||
|
||||
func (f *FourslashTest) VerifySemanticTokens(t *testing.T, expected []SemanticToken) {
|
||||
t.Helper()
|
||||
|
||||
params := &lsproto.SemanticTokensParams{
|
||||
TextDocument: lsproto.TextDocumentIdentifier{
|
||||
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
|
||||
},
|
||||
}
|
||||
|
||||
result := sendRequest(t, f, lsproto.TextDocumentSemanticTokensFullInfo, params)
|
||||
|
||||
if result.SemanticTokens == nil {
|
||||
if len(expected) == 0 {
|
||||
return
|
||||
}
|
||||
t.Fatal("Expected semantic tokens but got nil")
|
||||
}
|
||||
|
||||
// Decode the semantic tokens using token types/modifiers from the test configuration
|
||||
actual := decodeSemanticTokens(f, result.SemanticTokens.Data, f.semanticTokenTypes, f.semanticTokenModifiers)
|
||||
|
||||
// Compare with expected
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatalf("Expected %d semantic tokens, got %d\n\nExpected:\n%s\n\nActual:\n%s",
|
||||
len(expected), len(actual),
|
||||
formatSemanticTokens(expected),
|
||||
formatSemanticTokens(actual))
|
||||
}
|
||||
|
||||
for i, exp := range expected {
|
||||
act := actual[i]
|
||||
if exp.Type != act.Type || exp.Text != act.Text {
|
||||
t.Errorf("Token %d mismatch:\n Expected: {Type: %q, Text: %q}\n Actual: {Type: %q, Text: %q}",
|
||||
i, exp.Type, exp.Text, act.Type, act.Text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeSemanticTokens(f *FourslashTest, data []uint32, tokenTypes, tokenModifiers []string) []SemanticToken {
|
||||
if len(data)%5 != 0 {
|
||||
panic(fmt.Sprintf("Invalid semantic tokens data length: %d", len(data)))
|
||||
}
|
||||
|
||||
scriptInfo := f.scriptInfos[f.activeFilename]
|
||||
converters := lsconv.NewConverters(lsproto.PositionEncodingKindUTF8, func(_ string) *lsconv.LSPLineMap {
|
||||
return scriptInfo.lineMap
|
||||
})
|
||||
|
||||
var tokens []SemanticToken
|
||||
prevLine := uint32(0)
|
||||
prevChar := uint32(0)
|
||||
|
||||
for i := 0; i < len(data); i += 5 {
|
||||
deltaLine := data[i]
|
||||
deltaChar := data[i+1]
|
||||
length := data[i+2]
|
||||
tokenTypeIdx := data[i+3]
|
||||
tokenModifierMask := data[i+4]
|
||||
|
||||
// Calculate absolute position
|
||||
line := prevLine + deltaLine
|
||||
var char uint32
|
||||
if deltaLine == 0 {
|
||||
char = prevChar + deltaChar
|
||||
} else {
|
||||
char = deltaChar
|
||||
}
|
||||
|
||||
// Get token type
|
||||
if int(tokenTypeIdx) >= len(tokenTypes) {
|
||||
panic(fmt.Sprintf("Token type index out of range: %d", tokenTypeIdx))
|
||||
}
|
||||
tokenType := tokenTypes[tokenTypeIdx]
|
||||
|
||||
// Get modifiers
|
||||
var modifiers []string
|
||||
for i, mod := range tokenModifiers {
|
||||
if tokenModifierMask&(1<<i) != 0 {
|
||||
modifiers = append(modifiers, mod)
|
||||
}
|
||||
}
|
||||
|
||||
// Build full type string (type.modifier1.modifier2)
|
||||
typeStr := tokenType
|
||||
if len(modifiers) > 0 {
|
||||
typeStr = typeStr + "." + strings.Join(modifiers, ".")
|
||||
}
|
||||
|
||||
// Get the text
|
||||
startPos := lsproto.Position{Line: line, Character: char}
|
||||
endPos := lsproto.Position{Line: line, Character: char + length}
|
||||
startOffset := int(converters.LineAndCharacterToPosition(scriptInfo, startPos))
|
||||
endOffset := int(converters.LineAndCharacterToPosition(scriptInfo, endPos))
|
||||
text := scriptInfo.content[startOffset:endOffset]
|
||||
|
||||
tokens = append(tokens, SemanticToken{
|
||||
Type: typeStr,
|
||||
Text: text,
|
||||
})
|
||||
|
||||
prevLine = line
|
||||
prevChar = char
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
func formatSemanticTokens(tokens []SemanticToken) string {
|
||||
var lines []string
|
||||
for i, tok := range tokens {
|
||||
lines = append(lines, fmt.Sprintf(" [%d] {Type: %q, Text: %q}", i, tok.Type, tok.Text))
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
53
tools/tsgo/internal/fourslash/skip_if_failing.go
Normal file
53
tools/tsgo/internal/fourslash/skip_if_failing.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package fourslash
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var failingTests = sync.OnceValue(func() map[string]struct{} {
|
||||
failingTestsSet := make(map[string]struct{})
|
||||
|
||||
// Get the path to failingTests.txt relative to this source file
|
||||
_, thisFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
return failingTestsSet
|
||||
}
|
||||
|
||||
failingTestsPath := filepath.Join(filepath.Dir(thisFile), "_scripts", "failingTests.txt") //nolint:forbidigo
|
||||
|
||||
file, err := os.Open(failingTestsPath) //nolint:forbidigo
|
||||
if err != nil {
|
||||
return failingTestsSet
|
||||
}
|
||||
defer file.Close() //nolint:forbidigo
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line != "" {
|
||||
failingTestsSet[line] = struct{}{}
|
||||
}
|
||||
}
|
||||
return failingTestsSet
|
||||
})
|
||||
|
||||
// SkipIfFailing checks if the current test is in the failingTests.txt file
|
||||
// and skips it unless the TSGO_FOURSLASH_IGNORE_FAILING environment variable is set.
|
||||
// This allows tests to be marked as failing without modifying the test files themselves.
|
||||
func SkipIfFailing(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if os.Getenv("TSGO_FOURSLASH_IGNORE_FAILING") != "" { //nolint:forbidigo
|
||||
return
|
||||
}
|
||||
|
||||
if _, found := failingTests()[t.Name()]; found {
|
||||
t.Skip("Test is in failingTests.txt")
|
||||
}
|
||||
}
|
||||
511
tools/tsgo/internal/fourslash/statebaseline.go
Normal file
511
tools/tsgo/internal/fourslash/statebaseline.go
Normal file
@@ -0,0 +1,511 @@
|
||||
package fourslash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/collections"
|
||||
"github.com/microsoft/typescript-go/internal/compiler"
|
||||
"github.com/microsoft/typescript-go/internal/json"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ls/lsconv"
|
||||
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||
"github.com/microsoft/typescript-go/internal/project"
|
||||
"github.com/microsoft/typescript-go/internal/testutil/fsbaselineutil"
|
||||
"github.com/microsoft/typescript-go/internal/testutil/lsptestutil"
|
||||
"github.com/microsoft/typescript-go/internal/tspath"
|
||||
"github.com/microsoft/typescript-go/internal/vfs/iovfs"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
type stateBaseline struct {
|
||||
baseline strings.Builder
|
||||
fsDiffer *fsbaselineutil.FSDiffer
|
||||
isInitialized bool
|
||||
|
||||
serializedProjects map[string]projectInfo
|
||||
serializedOpenFiles map[string]*openFileInfo
|
||||
serializedConfigFileRegistry *project.ConfigFileRegistry
|
||||
}
|
||||
|
||||
func newStateBaseline(fsFromMap iovfs.FsWithSys) *stateBaseline {
|
||||
stateBaseline := &stateBaseline{
|
||||
fsDiffer: &fsbaselineutil.FSDiffer{
|
||||
FS: fsFromMap,
|
||||
WrittenFiles: &collections.SyncSet[string]{},
|
||||
},
|
||||
}
|
||||
fmt.Fprintf(&stateBaseline.baseline, "UseCaseSensitiveFileNames: %v\n", fsFromMap.UseCaseSensitiveFileNames())
|
||||
stateBaseline.fsDiffer.BaselineFSwithDiff(&stateBaseline.baseline)
|
||||
return stateBaseline
|
||||
}
|
||||
|
||||
type requestOrMessage struct {
|
||||
Method lsproto.Method `json:"method"`
|
||||
Params any `json:"params,omitzero"`
|
||||
}
|
||||
|
||||
func (f *FourslashTest) baselineRequestOrNotification(t *testing.T, method lsproto.Method, params any) {
|
||||
t.Helper()
|
||||
|
||||
if !f.testData.isStateBaseliningEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
res, _ := json.Marshal(requestOrMessage{method, params}, json.WithIndent(" "))
|
||||
f.stateBaseline.baseline.WriteString("\n")
|
||||
f.stateBaseline.baseline.Write(res)
|
||||
f.stateBaseline.baseline.WriteString("\n")
|
||||
f.stateBaseline.isInitialized = true
|
||||
}
|
||||
|
||||
func (f *FourslashTest) baselineProjectsAfterNotification(t *testing.T, fileName string) {
|
||||
t.Helper()
|
||||
if !f.testData.isStateBaseliningEnabled() {
|
||||
return
|
||||
}
|
||||
// Do hover so we have snapshot to check things on!!
|
||||
_, _, resultOk := lsptestutil.SendRequest(t, f.client, lsproto.TextDocumentHoverInfo, &lsproto.HoverParams{
|
||||
TextDocument: lsproto.TextDocumentIdentifier{
|
||||
Uri: lsconv.FileNameToDocumentURI(fileName),
|
||||
},
|
||||
Position: lsproto.Position{
|
||||
Line: uint32(0),
|
||||
Character: uint32(0),
|
||||
},
|
||||
})
|
||||
assert.Assert(t, resultOk)
|
||||
f.baselineState(t)
|
||||
}
|
||||
|
||||
func (f *FourslashTest) baselineState(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if !f.testData.isStateBaseliningEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
serialized := f.serializedState(t)
|
||||
if serialized != "" {
|
||||
f.stateBaseline.baseline.WriteString("\n")
|
||||
f.stateBaseline.baseline.WriteString(serialized)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FourslashTest) serializedState(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
var builder strings.Builder
|
||||
f.stateBaseline.fsDiffer.BaselineFSwithDiff(&builder)
|
||||
if strings.TrimSpace(builder.String()) == "" {
|
||||
builder.Reset()
|
||||
}
|
||||
|
||||
f.printStateDiff(t, &builder)
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type projectInfo = *compiler.Program
|
||||
|
||||
type openFileInfo struct {
|
||||
defaultProjectName string
|
||||
allProjects []string
|
||||
}
|
||||
|
||||
type diffTableOptions struct {
|
||||
indent string
|
||||
sortKeys bool
|
||||
}
|
||||
|
||||
type diffTable struct {
|
||||
diff collections.OrderedMap[string, string]
|
||||
options diffTableOptions
|
||||
}
|
||||
|
||||
func (d *diffTable) add(key, value string) {
|
||||
d.diff.Set(key, value)
|
||||
}
|
||||
|
||||
func (d *diffTable) print(w io.Writer, header string) {
|
||||
count := d.diff.Size()
|
||||
if count == 0 {
|
||||
return
|
||||
}
|
||||
if header != "" {
|
||||
fmt.Fprintf(w, "%s%s\n", d.options.indent, header)
|
||||
}
|
||||
diffKeys := make([]string, 0, count)
|
||||
keyWidth := 0
|
||||
indent := d.options.indent + " "
|
||||
for key := range d.diff.Keys() {
|
||||
keyWidth = max(keyWidth, len(key))
|
||||
diffKeys = append(diffKeys, key)
|
||||
}
|
||||
if d.options.sortKeys {
|
||||
slices.Sort(diffKeys)
|
||||
}
|
||||
|
||||
for _, key := range diffKeys {
|
||||
value := d.diff.GetOrZero(key)
|
||||
fmt.Fprintf(w, "%s%-*s %s\n", indent, keyWidth+1, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
type diffTableWriter struct {
|
||||
hasChange bool
|
||||
header string
|
||||
diffs map[string]func(io.Writer)
|
||||
}
|
||||
|
||||
func newDiffTableWriter(header string) *diffTableWriter {
|
||||
return &diffTableWriter{header: header, diffs: make(map[string]func(io.Writer))}
|
||||
}
|
||||
|
||||
func (d *diffTableWriter) setHasChange() {
|
||||
d.hasChange = true
|
||||
}
|
||||
|
||||
func (d *diffTableWriter) add(key string, fn func(io.Writer)) {
|
||||
d.diffs[key] = fn
|
||||
}
|
||||
|
||||
func (d *diffTableWriter) print(w io.Writer) {
|
||||
if d.hasChange {
|
||||
fmt.Fprintf(w, "%s::\n", d.header)
|
||||
keys := slices.Collect(maps.Keys(d.diffs))
|
||||
slices.Sort(keys)
|
||||
for _, key := range keys {
|
||||
d.diffs[key](w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func areIterSeqEqual(a, b iter.Seq[tspath.Path]) bool {
|
||||
aSlice := slices.Collect(a)
|
||||
bSlice := slices.Collect(b)
|
||||
slices.Sort(aSlice)
|
||||
slices.Sort(bSlice)
|
||||
return slices.Equal(aSlice, bSlice)
|
||||
}
|
||||
|
||||
func printSlicesWithDiffTable(w io.Writer, header string, newSlice []string, getOldSlice func() []string, options diffTableOptions, topChange string, isDefault func(entry string) bool) {
|
||||
var oldSlice []string
|
||||
if topChange == "*modified*" {
|
||||
oldSlice = getOldSlice()
|
||||
}
|
||||
table := diffTable{options: options}
|
||||
for _, entry := range newSlice {
|
||||
entryChange := ""
|
||||
if isDefault != nil && isDefault(entry) {
|
||||
entryChange = "(default) "
|
||||
}
|
||||
if topChange == "*modified*" && !slices.Contains(oldSlice, entry) {
|
||||
entryChange = "*new*"
|
||||
}
|
||||
table.add(entry, entryChange)
|
||||
}
|
||||
if topChange == "*modified*" {
|
||||
for _, entry := range oldSlice {
|
||||
if !slices.Contains(newSlice, entry) {
|
||||
table.add(entry, "*deleted*")
|
||||
}
|
||||
}
|
||||
}
|
||||
table.print(w, header)
|
||||
}
|
||||
|
||||
func sliceFromIterSeqPath(seq iter.Seq[tspath.Path]) []string {
|
||||
var result []string
|
||||
for path := range seq {
|
||||
result = append(result, string(path))
|
||||
}
|
||||
slices.Sort(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func printPathIterSeqWithDiffTable(w io.Writer, header string, newIterSeq iter.Seq[tspath.Path], getOldIterSeq func() iter.Seq[tspath.Path], options diffTableOptions, topChange string) {
|
||||
printSlicesWithDiffTable(
|
||||
w,
|
||||
header,
|
||||
sliceFromIterSeqPath(newIterSeq),
|
||||
func() []string { return sliceFromIterSeqPath(getOldIterSeq()) },
|
||||
options,
|
||||
topChange,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *FourslashTest) printStateDiff(t *testing.T, w io.Writer) {
|
||||
if !f.stateBaseline.isInitialized {
|
||||
return
|
||||
}
|
||||
session := f.client.Server.Session()
|
||||
snapshot := session.Snapshot()
|
||||
|
||||
f.printProjectsDiff(t, snapshot, w)
|
||||
f.printOpenFilesDiff(t, snapshot, w)
|
||||
f.printConfigFileRegistryDiff(t, snapshot, w)
|
||||
}
|
||||
|
||||
func (f *FourslashTest) printProjectsDiff(t *testing.T, snapshot *project.Snapshot, w io.Writer) {
|
||||
t.Helper()
|
||||
|
||||
currentProjects := make(map[string]projectInfo)
|
||||
options := diffTableOptions{indent: " "}
|
||||
projectsDiffTable := newDiffTableWriter("Projects")
|
||||
|
||||
for _, project := range snapshot.ProjectCollection.Projects() {
|
||||
program := project.GetProgram()
|
||||
var oldProgram *compiler.Program
|
||||
currentProjects[project.Name()] = program
|
||||
projectChange := ""
|
||||
if existing, ok := f.stateBaseline.serializedProjects[project.Name()]; ok {
|
||||
oldProgram = existing
|
||||
if oldProgram != program {
|
||||
projectChange = "*modified*"
|
||||
projectsDiffTable.setHasChange()
|
||||
} else {
|
||||
projectChange = ""
|
||||
}
|
||||
} else {
|
||||
projectChange = "*new*"
|
||||
projectsDiffTable.setHasChange()
|
||||
}
|
||||
|
||||
projectsDiffTable.add(project.Name(), func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] %s\n", project.Name(), projectChange)
|
||||
subDiff := diffTable{options: options}
|
||||
if program != nil {
|
||||
for _, file := range program.GetSourceFiles() {
|
||||
fileDiff := ""
|
||||
// No need to write "*new*" for files as its obvious
|
||||
fileName := file.FileName()
|
||||
if projectChange == "*modified*" {
|
||||
if oldProgram == nil {
|
||||
if !isLibFile(fileName) {
|
||||
fileDiff = "*new*"
|
||||
}
|
||||
} else if oldFile := oldProgram.GetSourceFileByPath(file.Path()); oldFile == nil {
|
||||
fileDiff = "*new*"
|
||||
} else if oldFile != file {
|
||||
fileDiff = "*modified*"
|
||||
}
|
||||
}
|
||||
if fileDiff != "" || !isLibFile(fileName) {
|
||||
subDiff.add(fileName, fileDiff)
|
||||
}
|
||||
}
|
||||
}
|
||||
if oldProgram != program && oldProgram != nil {
|
||||
for _, file := range oldProgram.GetSourceFiles() {
|
||||
if program == nil || program.GetSourceFileByPath(file.Path()) == nil {
|
||||
subDiff.add(file.FileName(), "*deleted*")
|
||||
}
|
||||
}
|
||||
}
|
||||
subDiff.print(w, "")
|
||||
})
|
||||
}
|
||||
|
||||
for projectName, info := range f.stateBaseline.serializedProjects {
|
||||
if _, found := currentProjects[projectName]; !found {
|
||||
projectsDiffTable.setHasChange()
|
||||
projectsDiffTable.add(projectName, func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] *deleted*\n", projectName)
|
||||
subDiff := diffTable{options: options}
|
||||
if info != nil {
|
||||
for _, file := range info.GetSourceFiles() {
|
||||
if fileName := file.FileName(); !isLibFile(fileName) {
|
||||
subDiff.add(fileName, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
subDiff.print(w, "")
|
||||
})
|
||||
}
|
||||
}
|
||||
f.stateBaseline.serializedProjects = currentProjects
|
||||
projectsDiffTable.print(w)
|
||||
}
|
||||
|
||||
func (f *FourslashTest) printOpenFilesDiff(t *testing.T, snapshot *project.Snapshot, w io.Writer) {
|
||||
t.Helper()
|
||||
|
||||
currentOpenFiles := make(map[string]*openFileInfo)
|
||||
filesDiffTable := newDiffTableWriter("Open Files")
|
||||
options := diffTableOptions{indent: " ", sortKeys: true}
|
||||
for fileName := range f.openFiles {
|
||||
path := tspath.ToPath(fileName, "/", f.vfs.UseCaseSensitiveFileNames())
|
||||
defaultProject := snapshot.ProjectCollection.GetDefaultProject(path)
|
||||
newFileInfo := &openFileInfo{}
|
||||
if defaultProject != nil {
|
||||
newFileInfo.defaultProjectName = defaultProject.Name()
|
||||
}
|
||||
for _, project := range snapshot.ProjectCollection.Projects() {
|
||||
if program := project.GetProgram(); program != nil && program.GetSourceFileByPath(path) != nil {
|
||||
newFileInfo.allProjects = append(newFileInfo.allProjects, project.Name())
|
||||
}
|
||||
}
|
||||
slices.Sort(newFileInfo.allProjects)
|
||||
currentOpenFiles[fileName] = newFileInfo
|
||||
openFileChange := ""
|
||||
var oldFileInfo *openFileInfo
|
||||
if existing, ok := f.stateBaseline.serializedOpenFiles[fileName]; ok {
|
||||
oldFileInfo = existing
|
||||
if existing.defaultProjectName != newFileInfo.defaultProjectName || !slices.Equal(existing.allProjects, newFileInfo.allProjects) {
|
||||
openFileChange = "*modified*"
|
||||
filesDiffTable.setHasChange()
|
||||
} else {
|
||||
openFileChange = ""
|
||||
}
|
||||
} else {
|
||||
openFileChange = "*new*"
|
||||
filesDiffTable.setHasChange()
|
||||
}
|
||||
|
||||
filesDiffTable.add(fileName, func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] %s\n", fileName, openFileChange)
|
||||
printSlicesWithDiffTable(
|
||||
w,
|
||||
"",
|
||||
newFileInfo.allProjects,
|
||||
func() []string { return oldFileInfo.allProjects },
|
||||
options,
|
||||
openFileChange,
|
||||
func(projectName string) bool { return projectName == newFileInfo.defaultProjectName },
|
||||
)
|
||||
})
|
||||
}
|
||||
for fileName := range f.stateBaseline.serializedOpenFiles {
|
||||
if _, found := currentOpenFiles[fileName]; !found {
|
||||
filesDiffTable.setHasChange()
|
||||
filesDiffTable.add(fileName, func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] *closed*\n", fileName)
|
||||
})
|
||||
}
|
||||
}
|
||||
f.stateBaseline.serializedOpenFiles = currentOpenFiles
|
||||
filesDiffTable.print(w)
|
||||
}
|
||||
|
||||
func (f *FourslashTest) printConfigFileRegistryDiff(t *testing.T, snapshot *project.Snapshot, w io.Writer) {
|
||||
t.Helper()
|
||||
configFileRegistry := snapshot.ProjectCollection.ConfigFileRegistry()
|
||||
|
||||
configDiffsTable := newDiffTableWriter("Config")
|
||||
configFileNamesDiffsTable := newDiffTableWriter("Config File Names")
|
||||
|
||||
if f.stateBaseline.serializedConfigFileRegistry == configFileRegistry {
|
||||
return
|
||||
}
|
||||
options := diffTableOptions{indent: " ", sortKeys: true}
|
||||
configFileRegistry.ForEachTestConfigEntry(func(path tspath.Path, entry *project.TestConfigEntry) {
|
||||
configChange := ""
|
||||
oldEntry := f.stateBaseline.serializedConfigFileRegistry.GetTestConfigEntry(path)
|
||||
if oldEntry == nil {
|
||||
configChange = "*new*"
|
||||
configDiffsTable.setHasChange()
|
||||
} else if oldEntry != entry {
|
||||
if !areIterSeqEqual(oldEntry.RetainingProjects, entry.RetainingProjects) ||
|
||||
!areIterSeqEqual(oldEntry.RetainingOpenFiles, entry.RetainingOpenFiles) ||
|
||||
!areIterSeqEqual(oldEntry.RetainingConfigs, entry.RetainingConfigs) {
|
||||
configChange = "*modified*"
|
||||
configDiffsTable.setHasChange()
|
||||
}
|
||||
}
|
||||
configDiffsTable.add(string(path), func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] %s\n", entry.FileName, configChange)
|
||||
// Print the details of the config entry
|
||||
var retainingProjectsModified string
|
||||
var retainingOpenFilesModified string
|
||||
var retainingConfigsModified string
|
||||
if configChange == "*modified*" {
|
||||
if !areIterSeqEqual(entry.RetainingProjects, oldEntry.RetainingProjects) {
|
||||
retainingProjectsModified = " *modified*"
|
||||
}
|
||||
if !areIterSeqEqual(entry.RetainingOpenFiles, oldEntry.RetainingOpenFiles) {
|
||||
retainingOpenFilesModified = " *modified*"
|
||||
}
|
||||
if !areIterSeqEqual(entry.RetainingConfigs, oldEntry.RetainingConfigs) {
|
||||
retainingConfigsModified = " *modified*"
|
||||
}
|
||||
}
|
||||
printPathIterSeqWithDiffTable(w, "RetainingProjects:"+retainingProjectsModified, entry.RetainingProjects, func() iter.Seq[tspath.Path] { return oldEntry.RetainingProjects }, options, configChange)
|
||||
printPathIterSeqWithDiffTable(w, "RetainingOpenFiles:"+retainingOpenFilesModified, entry.RetainingOpenFiles, func() iter.Seq[tspath.Path] { return oldEntry.RetainingOpenFiles }, options, configChange)
|
||||
printPathIterSeqWithDiffTable(w, "RetainingConfigs:"+retainingConfigsModified, entry.RetainingConfigs, func() iter.Seq[tspath.Path] { return oldEntry.RetainingConfigs }, options, configChange)
|
||||
})
|
||||
})
|
||||
configFileRegistry.ForEachTestConfigFileNamesEntry(func(path tspath.Path, entry *project.TestConfigFileNamesEntry) {
|
||||
configFileNamesChange := ""
|
||||
oldEntry := f.stateBaseline.serializedConfigFileRegistry.GetTestConfigFileNamesEntry(path)
|
||||
if oldEntry == nil {
|
||||
configFileNamesChange = "*new*"
|
||||
configFileNamesDiffsTable.setHasChange()
|
||||
} else if oldEntry.NearestConfigFileName != entry.NearestConfigFileName ||
|
||||
!maps.Equal(oldEntry.Ancestors, entry.Ancestors) {
|
||||
configFileNamesChange = "*modified*"
|
||||
configFileNamesDiffsTable.setHasChange()
|
||||
}
|
||||
configFileNamesDiffsTable.add(string(path), func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] %s\n", path, configFileNamesChange)
|
||||
var nearestConfigFileNameModified string
|
||||
var ancestorDiffModified string
|
||||
if configFileNamesChange == "*modified*" {
|
||||
if oldEntry.NearestConfigFileName != entry.NearestConfigFileName {
|
||||
nearestConfigFileNameModified = " *modified*"
|
||||
}
|
||||
if !maps.Equal(oldEntry.Ancestors, entry.Ancestors) {
|
||||
ancestorDiffModified = " *modified*"
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, " NearestConfigFileName: %s%s\n", entry.NearestConfigFileName, nearestConfigFileNameModified)
|
||||
ancestorDiff := diffTable{options: options}
|
||||
for config, ancestorOfConfig := range entry.Ancestors {
|
||||
ancestorChange := ""
|
||||
if configFileNamesChange == "*modified*" {
|
||||
if oldConfigFileName, ok := oldEntry.Ancestors[config]; ok {
|
||||
if oldConfigFileName != ancestorOfConfig {
|
||||
ancestorChange = "*modified*"
|
||||
}
|
||||
} else {
|
||||
ancestorChange = "*new*"
|
||||
}
|
||||
}
|
||||
ancestorDiff.add(config, fmt.Sprintf("%s %s", ancestorOfConfig, ancestorChange))
|
||||
}
|
||||
if configFileNamesChange == "*modified*" {
|
||||
for ancestorPath, oldConfigFileName := range oldEntry.Ancestors {
|
||||
if _, ok := entry.Ancestors[ancestorPath]; !ok {
|
||||
ancestorDiff.add(ancestorPath, oldConfigFileName+" *deleted*")
|
||||
}
|
||||
}
|
||||
}
|
||||
ancestorDiff.print(w, "Ancestors:"+ancestorDiffModified)
|
||||
})
|
||||
})
|
||||
|
||||
f.stateBaseline.serializedConfigFileRegistry.ForEachTestConfigEntry(func(path tspath.Path, entry *project.TestConfigEntry) {
|
||||
if configFileRegistry.GetTestConfigEntry(path) == nil {
|
||||
configDiffsTable.setHasChange()
|
||||
configDiffsTable.add(string(path), func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] *deleted*\n", entry.FileName)
|
||||
})
|
||||
}
|
||||
})
|
||||
f.stateBaseline.serializedConfigFileRegistry.ForEachTestConfigFileNamesEntry(func(path tspath.Path, entry *project.TestConfigFileNamesEntry) {
|
||||
if configFileRegistry.GetTestConfigFileNamesEntry(path) == nil {
|
||||
configFileNamesDiffsTable.setHasChange()
|
||||
configFileNamesDiffsTable.add(string(path), func(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] *deleted*\n", path)
|
||||
})
|
||||
}
|
||||
})
|
||||
f.stateBaseline.serializedConfigFileRegistry = configFileRegistry
|
||||
configDiffsTable.print(w)
|
||||
configFileNamesDiffsTable.print(w)
|
||||
}
|
||||
509
tools/tsgo/internal/fourslash/test_parser.go
Normal file
509
tools/tsgo/internal/fourslash/test_parser.go
Normal file
@@ -0,0 +1,509 @@
|
||||
package fourslash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/core"
|
||||
"github.com/microsoft/typescript-go/internal/json"
|
||||
"github.com/microsoft/typescript-go/internal/ls/lsconv"
|
||||
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||
"github.com/microsoft/typescript-go/internal/stringutil"
|
||||
"github.com/microsoft/typescript-go/internal/testrunner"
|
||||
"github.com/microsoft/typescript-go/internal/tspath"
|
||||
)
|
||||
|
||||
// Inserted in source files by surrounding desired text
|
||||
// in a range with `[|` and `|]`. For example,
|
||||
//
|
||||
// [|text in range|]
|
||||
//
|
||||
// is a range with `text in range` "selected".
|
||||
type RangeMarker struct {
|
||||
fileName string
|
||||
Range core.TextRange
|
||||
LSRange lsproto.Range
|
||||
Marker *Marker
|
||||
}
|
||||
|
||||
func (r *RangeMarker) LSPos() lsproto.Position {
|
||||
return r.LSRange.Start
|
||||
}
|
||||
|
||||
func (r *RangeMarker) FileName() string {
|
||||
return r.fileName
|
||||
}
|
||||
|
||||
func (r *RangeMarker) GetName() *string {
|
||||
if r.Marker == nil {
|
||||
return nil
|
||||
}
|
||||
return r.Marker.Name
|
||||
}
|
||||
|
||||
func (r *RangeMarker) LSLocation() lsproto.Location {
|
||||
return lsproto.Location{
|
||||
Uri: lsconv.FileNameToDocumentURI(r.fileName),
|
||||
Range: r.LSRange,
|
||||
}
|
||||
}
|
||||
|
||||
type Marker struct {
|
||||
fileName string
|
||||
Position int
|
||||
LSPosition lsproto.Position
|
||||
Name *string // `nil` for anonymous markers such as `{| "foo": "bar" |}`
|
||||
Data map[string]any
|
||||
}
|
||||
|
||||
func (m *Marker) LSPos() lsproto.Position {
|
||||
return m.LSPosition
|
||||
}
|
||||
|
||||
func (m *Marker) FileName() string {
|
||||
return m.fileName
|
||||
}
|
||||
|
||||
func (m *Marker) GetName() *string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
func (m *Marker) MakerWithSymlink(fileName string) *Marker {
|
||||
return &Marker{
|
||||
fileName: fileName,
|
||||
Position: m.Position,
|
||||
LSPosition: m.LSPosition,
|
||||
Name: m.Name,
|
||||
Data: m.Data,
|
||||
}
|
||||
}
|
||||
|
||||
type MarkerOrRange interface {
|
||||
FileName() string
|
||||
LSPos() lsproto.Position
|
||||
GetName() *string
|
||||
}
|
||||
|
||||
type TestData struct {
|
||||
Files []*TestFileInfo
|
||||
MarkerPositions map[string]*Marker
|
||||
Markers []*Marker
|
||||
Symlinks map[string]string
|
||||
GlobalOptions map[string]string
|
||||
Ranges []*RangeMarker
|
||||
}
|
||||
|
||||
func (t *TestData) isStateBaseliningEnabled() bool {
|
||||
return isStateBaseliningEnabled(t.GlobalOptions)
|
||||
}
|
||||
|
||||
type testFileWithMarkers struct {
|
||||
file *TestFileInfo
|
||||
markers []*Marker
|
||||
ranges []*RangeMarker
|
||||
}
|
||||
|
||||
func isStateBaseliningEnabled(globalOptions map[string]string) bool {
|
||||
return globalOptions["statebaseline"] == "true"
|
||||
}
|
||||
|
||||
func ParseTestData(t *testing.T, contents string, fileName string) TestData {
|
||||
// List of all the subfiles we've parsed out
|
||||
var files []*TestFileInfo
|
||||
|
||||
markerPositions := make(map[string]*Marker)
|
||||
var markers []*Marker
|
||||
var ranges []*RangeMarker
|
||||
|
||||
filesWithMarker, symlinks, _, globalOptions, e := testrunner.ParseTestFilesAndSymlinksWithOptions(
|
||||
contents,
|
||||
fileName,
|
||||
parseFileContent,
|
||||
testrunner.ParseTestFilesOptions{
|
||||
AllowImplicitFirstFile: true,
|
||||
},
|
||||
)
|
||||
if e != nil {
|
||||
t.Fatalf("Error parsing fourslash data: %s", e.Error())
|
||||
}
|
||||
|
||||
hasTSConfig := false
|
||||
for _, file := range filesWithMarker {
|
||||
files = append(files, file.file)
|
||||
hasTSConfig = hasTSConfig || isConfigFile(file.file.fileName)
|
||||
|
||||
markers = append(markers, file.markers...)
|
||||
ranges = append(ranges, file.ranges...)
|
||||
for _, marker := range file.markers {
|
||||
if marker.Name == nil {
|
||||
if marker.Data != nil {
|
||||
// The marker is an anonymous object marker, which does not need a name. Markers are only set into markerPositions if they have a name
|
||||
continue
|
||||
}
|
||||
t.Fatalf(`Marker at position %v is unnamed`, marker.Position)
|
||||
}
|
||||
if existing, ok := markerPositions[*marker.Name]; ok {
|
||||
t.Fatalf(`Duplicate marker name: "%s" at %v and %v`, *marker.Name, marker.Position, existing.Position)
|
||||
}
|
||||
markerPositions[*marker.Name] = marker
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if hasTSConfig && hasUnsupportedGlobalOptionsWithConfig(globalOptions) && !isStateBaseliningEnabled(globalOptions) {
|
||||
t.Fatalf("It is not allowed to use global options along with config files.")
|
||||
}
|
||||
|
||||
return TestData{
|
||||
Files: files,
|
||||
MarkerPositions: markerPositions,
|
||||
Markers: markers,
|
||||
Symlinks: symlinks,
|
||||
GlobalOptions: globalOptions,
|
||||
Ranges: ranges,
|
||||
}
|
||||
}
|
||||
|
||||
func hasUnsupportedGlobalOptionsWithConfig(globalOptions map[string]string) bool {
|
||||
for option := range globalOptions {
|
||||
switch strings.ToLower(option) {
|
||||
case "symlink", "link", "usecasesensitivefilenames":
|
||||
continue
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isConfigFile(fileName string) bool {
|
||||
fileName = strings.ToLower(fileName)
|
||||
return strings.HasSuffix(fileName, "tsconfig.json") || strings.HasSuffix(fileName, "jsconfig.json")
|
||||
}
|
||||
|
||||
type locationInformation struct {
|
||||
position int
|
||||
sourcePosition int
|
||||
sourceLine int
|
||||
sourceColumn int
|
||||
}
|
||||
|
||||
type rangeLocationInformation struct {
|
||||
locationInformation
|
||||
marker *Marker
|
||||
}
|
||||
|
||||
type TestFileInfo struct {
|
||||
fileName string
|
||||
// The contents of the file (with markers, etc stripped out)
|
||||
Content string
|
||||
emit bool
|
||||
}
|
||||
|
||||
// FileName implements lsconv.Script.
|
||||
func (t *TestFileInfo) FileName() string {
|
||||
return t.fileName
|
||||
}
|
||||
|
||||
// Text implements lsconv.Script.
|
||||
func (t *TestFileInfo) Text() string {
|
||||
return t.Content
|
||||
}
|
||||
|
||||
var _ lsconv.Script = (*TestFileInfo)(nil)
|
||||
|
||||
const emitThisFileOption = "emitthisfile"
|
||||
|
||||
type parserState int
|
||||
|
||||
const (
|
||||
stateNone parserState = iota
|
||||
stateInSlashStarMarker
|
||||
stateInObjectMarker
|
||||
)
|
||||
|
||||
func parseFileContent(fileName string, content string, fileOptions map[string]string) (*testFileWithMarkers, error) {
|
||||
fileName = tspath.GetNormalizedAbsolutePath(fileName, "/")
|
||||
content = chompLeadingSpace(content)
|
||||
|
||||
// The file content (minus metacharacters) so far
|
||||
var output strings.Builder
|
||||
|
||||
var markers []*Marker
|
||||
|
||||
/// A stack of the open range markers that are still unclosed
|
||||
openRanges := []rangeLocationInformation{}
|
||||
/// A list of closed ranges we've collected so far
|
||||
rangeMarkers := []*RangeMarker{}
|
||||
|
||||
// The total number of metacharacters removed from the file (so far)
|
||||
difference := 0
|
||||
|
||||
// One-based current position data
|
||||
line := 1
|
||||
column := 1
|
||||
|
||||
// The current marker (or maybe multi-line comment?) we're parsing, possibly
|
||||
var openMarker *locationInformation
|
||||
|
||||
// The latest position of the start of an unflushed plain text area
|
||||
lastNormalCharPosition := 0
|
||||
|
||||
flush := func(lastSafeCharIndex int) {
|
||||
if lastSafeCharIndex != -1 {
|
||||
output.WriteString(content[lastNormalCharPosition:lastSafeCharIndex])
|
||||
} else {
|
||||
output.WriteString(content[lastNormalCharPosition:])
|
||||
}
|
||||
}
|
||||
|
||||
state := stateNone
|
||||
previousCharacter, i := utf8.DecodeRuneInString(content)
|
||||
var size int
|
||||
var currentCharacter rune
|
||||
for ; i < len(content); i = i + size {
|
||||
currentCharacter, size = utf8.DecodeRuneInString(content[i:])
|
||||
switch state {
|
||||
case stateNone:
|
||||
if previousCharacter == '[' && currentCharacter == '|' {
|
||||
// found a range start
|
||||
openRanges = append(openRanges, rangeLocationInformation{
|
||||
locationInformation: locationInformation{
|
||||
position: (i - 1) - difference,
|
||||
sourcePosition: i - 1,
|
||||
sourceLine: line,
|
||||
sourceColumn: column,
|
||||
},
|
||||
})
|
||||
// copy all text up to marker position
|
||||
flush(i - 1)
|
||||
lastNormalCharPosition = i + 1
|
||||
difference += 2
|
||||
} else if previousCharacter == '|' && currentCharacter == ']' {
|
||||
// found a range end
|
||||
if len(openRanges) == 0 {
|
||||
return nil, reportError(fileName, line, column, "Found range end with no matching start.")
|
||||
}
|
||||
rangeStart := openRanges[len(openRanges)-1]
|
||||
openRanges = openRanges[:len(openRanges)-1]
|
||||
|
||||
closedRange := &RangeMarker{
|
||||
fileName: fileName,
|
||||
Range: core.NewTextRange(rangeStart.position, (i-1)-difference),
|
||||
Marker: rangeStart.marker,
|
||||
}
|
||||
|
||||
rangeMarkers = append(rangeMarkers, closedRange)
|
||||
|
||||
// copy all text up to range marker position
|
||||
flush(i - 1)
|
||||
lastNormalCharPosition = i + 1
|
||||
difference += 2
|
||||
} else if previousCharacter == '/' && currentCharacter == '*' && (i+1 >= len(content) || content[i+1] != '/') {
|
||||
// found a possible marker start
|
||||
state = stateInSlashStarMarker
|
||||
openMarker = &locationInformation{
|
||||
position: (i - 1) - difference,
|
||||
sourcePosition: i - 1,
|
||||
sourceLine: line,
|
||||
sourceColumn: column - 1,
|
||||
}
|
||||
} else if previousCharacter == '{' && currentCharacter == '|' {
|
||||
// found an object marker start
|
||||
state = stateInObjectMarker
|
||||
openMarker = &locationInformation{
|
||||
position: (i - 1) - difference,
|
||||
sourcePosition: i - 1,
|
||||
sourceLine: line,
|
||||
sourceColumn: column,
|
||||
}
|
||||
flush(i - 1)
|
||||
}
|
||||
case stateInObjectMarker:
|
||||
// Object markers are only ever terminated by |} and have no content restrictions
|
||||
if previousCharacter == '|' && currentCharacter == '}' {
|
||||
objectMarkerData := strings.TrimSpace(content[openMarker.sourcePosition+2 : i-1])
|
||||
marker, e := getObjectMarker(fileName, openMarker, objectMarkerData)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if len(openRanges) > 0 {
|
||||
openRanges[len(openRanges)-1].marker = marker
|
||||
}
|
||||
markers = append(markers, marker)
|
||||
|
||||
// Set the current start to point to the end of the current marker to ignore its text
|
||||
lastNormalCharPosition = i + 1
|
||||
difference += i + 1 - openMarker.sourcePosition
|
||||
|
||||
// Reset the state
|
||||
openMarker = nil
|
||||
state = stateNone
|
||||
}
|
||||
case stateInSlashStarMarker:
|
||||
if previousCharacter == '*' && currentCharacter == '/' {
|
||||
// Record the marker
|
||||
// start + 2 to ignore the */, -1 on the end to ignore the * (/ is next)
|
||||
markerNameText := strings.TrimSpace(content[openMarker.sourcePosition+2 : i-1])
|
||||
marker := &Marker{
|
||||
fileName: fileName,
|
||||
Position: openMarker.position,
|
||||
Name: &markerNameText,
|
||||
}
|
||||
if len(openRanges) > 0 {
|
||||
openRanges[len(openRanges)-1].marker = marker
|
||||
}
|
||||
markers = append(markers, marker)
|
||||
|
||||
// Set the current start to point to the end of the current marker to ignore its text
|
||||
flush(openMarker.sourcePosition)
|
||||
lastNormalCharPosition = i + 1
|
||||
difference += i + 1 - openMarker.sourcePosition
|
||||
|
||||
// Reset the state
|
||||
openMarker = nil
|
||||
state = stateNone
|
||||
} else if !(stringutil.IsDigit(currentCharacter) ||
|
||||
stringutil.IsASCIILetter(currentCharacter) ||
|
||||
currentCharacter == '$' ||
|
||||
currentCharacter == '_') { // Invalid marker character
|
||||
if currentCharacter == '*' && i < len(content)-1 && content[i+1] == '/' {
|
||||
// The marker is about to be closed, ignore the 'invalid' char
|
||||
} else {
|
||||
// We've hit a non-valid marker character, so we were actually in a block comment
|
||||
// Bail out the text we've gathered so far back into the output
|
||||
flush(i)
|
||||
lastNormalCharPosition = i
|
||||
openMarker = nil
|
||||
state = stateNone
|
||||
}
|
||||
}
|
||||
}
|
||||
if currentCharacter == '\n' && previousCharacter == '\r' {
|
||||
// Ignore trailing \n after \r
|
||||
continue
|
||||
} else if currentCharacter == '\n' || currentCharacter == '\r' {
|
||||
line++
|
||||
column = 1
|
||||
continue
|
||||
}
|
||||
column++
|
||||
if i >= lastNormalCharPosition {
|
||||
previousCharacter = currentCharacter
|
||||
} else {
|
||||
previousCharacter = utf8.RuneError // reset to avoid accidentally reusing marker delimiters as part of other markers
|
||||
}
|
||||
}
|
||||
|
||||
// Add the remaining text
|
||||
flush(-1)
|
||||
|
||||
if len(openRanges) > 0 {
|
||||
openRange := openRanges[0]
|
||||
return nil, reportError(fileName, openRange.sourceLine, openRange.sourceColumn, "Unterminated range.")
|
||||
}
|
||||
|
||||
if openMarker != nil {
|
||||
return nil, reportError(fileName, openMarker.sourceLine, openMarker.sourceColumn, "Unterminated marker.")
|
||||
}
|
||||
|
||||
outputString := output.String()
|
||||
// Set LS positions for markers
|
||||
lineMap := lsconv.ComputeLSPLineStarts(outputString)
|
||||
converters := lsconv.NewConverters(lsproto.PositionEncodingKindUTF8, func(_ string) *lsconv.LSPLineMap {
|
||||
return lineMap
|
||||
})
|
||||
|
||||
emit := fileOptions[emitThisFileOption] == "true"
|
||||
|
||||
testFileInfo := &TestFileInfo{
|
||||
fileName: fileName,
|
||||
Content: outputString,
|
||||
emit: emit,
|
||||
}
|
||||
|
||||
slices.SortStableFunc(rangeMarkers, func(a, b *RangeMarker) int {
|
||||
if a.Range.Pos() != b.Range.Pos() {
|
||||
return a.Range.Pos() - b.Range.Pos()
|
||||
}
|
||||
return b.Range.End() - a.Range.End()
|
||||
})
|
||||
|
||||
for _, marker := range markers {
|
||||
marker.LSPosition = converters.PositionToLineAndCharacter(testFileInfo, core.TextPos(marker.Position))
|
||||
}
|
||||
for _, rangeMarker := range rangeMarkers {
|
||||
rangeMarker.LSRange = lsproto.Range{
|
||||
Start: converters.PositionToLineAndCharacter(testFileInfo, core.TextPos(rangeMarker.Range.Pos())),
|
||||
End: converters.PositionToLineAndCharacter(testFileInfo, core.TextPos(rangeMarker.Range.End())),
|
||||
}
|
||||
}
|
||||
|
||||
return &testFileWithMarkers{
|
||||
file: testFileInfo,
|
||||
markers: markers,
|
||||
ranges: rangeMarkers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getObjectMarker(fileName string, location *locationInformation, text string) (*Marker, error) {
|
||||
// Attempt to parse the marker value as JSON
|
||||
var v any
|
||||
e := json.Unmarshal([]byte("{ "+text+" }"), &v)
|
||||
|
||||
if e != nil {
|
||||
return nil, reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text "+text)
|
||||
}
|
||||
markerValue, ok := v.(map[string]any)
|
||||
if !ok || len(markerValue) == 0 {
|
||||
return nil, reportError(fileName, location.sourceLine, location.sourceColumn, "Object markers can not be empty")
|
||||
}
|
||||
|
||||
marker := &Marker{
|
||||
fileName: fileName,
|
||||
Position: location.position,
|
||||
Data: markerValue,
|
||||
}
|
||||
|
||||
// Object markers can be anonymous
|
||||
if markerValue["name"] != nil {
|
||||
if name, ok := markerValue["name"].(string); ok && name != "" {
|
||||
marker.Name = &name
|
||||
}
|
||||
}
|
||||
|
||||
return marker, nil
|
||||
}
|
||||
|
||||
func reportError(fileName string, line int, col int, message string) error {
|
||||
return &fourslashError{fmt.Sprintf("%v (%v,%v): %v", fileName, line, col, message)}
|
||||
}
|
||||
|
||||
func chompLeadingSpace(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for _, line := range lines {
|
||||
if len(line) > 0 && line[0] != ' ' {
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]string, len(lines))
|
||||
for i, line := range lines {
|
||||
if len(line) > 0 {
|
||||
result[i] = line[1:]
|
||||
}
|
||||
}
|
||||
return strings.Join(result, "\n")
|
||||
}
|
||||
|
||||
type fourslashError struct {
|
||||
err string
|
||||
}
|
||||
|
||||
func (e *fourslashError) Error() string {
|
||||
return e.err
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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"`},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
122
tools/tsgo/internal/fourslash/tests/autoImportCompletion_test.go
Normal file
122
tools/tsgo/internal/fourslash/tests/autoImportCompletion_test.go
Normal 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{""})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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)),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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)),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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`),
|
||||
})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
@@ -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"},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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{""})
|
||||
}
|
||||
43
tools/tsgo/internal/fourslash/tests/basicBackspace_test.go
Normal file
43
tools/tsgo/internal/fourslash/tests/basicBackspace_test.go
Normal 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"},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
44
tools/tsgo/internal/fourslash/tests/basicEdit_test.go
Normal file
44
tools/tsgo/internal/fourslash/tests/basicEdit_test.go
Normal 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",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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] ",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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)),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
33
tools/tsgo/internal/fourslash/tests/basicQuickInfo_test.go
Normal file
33
tools/tsgo/internal/fourslash/tests/basicQuickInfo_test.go
Normal 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)")
|
||||
}
|
||||
43
tools/tsgo/internal/fourslash/tests/basicReplaceLine_test.go
Normal file
43
tools/tsgo/internal/fourslash/tests/basicReplaceLine_test.go
Normal 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"},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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`, "")
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
@@ -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");`,
|
||||
})
|
||||
}
|
||||
@@ -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;`,
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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*/)
|
||||
}
|
||||
@@ -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),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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...),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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)),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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{},
|
||||
})
|
||||
}
|
||||
@@ -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",
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user