internal/ls/autoimportstypes.go (176 lines of code) (raw):

package ls import ( "fmt" "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/checker" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/lsp/lsproto" "github.com/microsoft/typescript-go/internal/modulespecifiers" ) //go:generate go tool golang.org/x/tools/cmd/stringer -type=ExportKind -output=autoImports_stringer_generated.go //go:generate go tool mvdan.cc/gofumpt -w autoImports_stringer_generated.go type ImportKind int const ( ImportKindNamed ImportKind = 0 ImportKindDefault ImportKind = 1 ImportKindNamespace ImportKind = 2 ImportKindCommonJS ImportKind = 3 ) type ExportKind int const ( ExportKindNamed ExportKind = 0 ExportKindDefault ExportKind = 1 ExportKindExportEquals ExportKind = 2 ExportKindUMD ExportKind = 3 ExportKindModule ExportKind = 4 ) type ImportFixKind int const ( // Sorted with the preferred fix coming first. ImportFixKindUseNamespace ImportFixKind = 0 ImportFixKindJsdocTypeImport ImportFixKind = 1 ImportFixKindAddToExisting ImportFixKind = 2 ImportFixKindAddNew ImportFixKind = 3 ImportFixKindPromoteTypeOnly ImportFixKind = 4 ) type AddAsTypeOnly int const ( // These should not be combined as bitflags, but are given powers of 2 values to // easily detect conflicts between `NotAllowed` and `Required` by giving them a unique sum. // They're also ordered in terms of increasing priority for a fix-all scenario (see // `reduceAddAsTypeOnlyValues`). AddAsTypeOnlyAllowed AddAsTypeOnly = 1 << 0 AddAsTypeOnlyRequired AddAsTypeOnly = 1 << 1 AddAsTypeOnlyNotAllowed AddAsTypeOnly = 1 << 2 ) type ImportFix struct { kind ImportFixKind isReExport *bool exportInfo *SymbolExportInfo // !!! | FutureSymbolExportInfo | undefined moduleSpecifierKind modulespecifiers.ResultKind moduleSpecifier string usagePosition *lsproto.Position namespacePrefix *string importClauseOrBindingPattern *ast.Node // ImportClause | ObjectBindingPattern importKind ImportKind // ImportKindDefault | ImportKindNamed addAsTypeOnly AddAsTypeOnly propertyName string // !!! not implemented useRequire bool typeOnlyAliasDeclaration *ast.Declaration // TypeOnlyAliasDeclaration } func (i *ImportFix) qualification() *Qualification { switch i.kind { case ImportFixKindAddNew: if i.usagePosition == nil || strPtrIsEmpty(i.namespacePrefix) { return nil } fallthrough case ImportFixKindUseNamespace: return &Qualification{ usagePosition: *i.usagePosition, namespacePrefix: *i.namespacePrefix, } } panic(fmt.Sprintf("no qualification with ImportFixKind %v", i.kind)) } type Qualification struct { usagePosition lsproto.Position namespacePrefix string } func getUseNamespaceImport( moduleSpecifier string, moduleSpecifierKind modulespecifiers.ResultKind, namespacePrefix string, usagePosition lsproto.Position, ) *ImportFix { return &ImportFix{ kind: ImportFixKindUseNamespace, moduleSpecifierKind: moduleSpecifierKind, moduleSpecifier: moduleSpecifier, usagePosition: ptrTo(usagePosition), namespacePrefix: strPtrTo(namespacePrefix), } } func getAddJsdocTypeImport( moduleSpecifier string, moduleSpecifierKind modulespecifiers.ResultKind, usagePosition *lsproto.Position, exportInfo *SymbolExportInfo, isReExport *bool, ) *ImportFix { return &ImportFix{ kind: ImportFixKindJsdocTypeImport, isReExport: isReExport, exportInfo: exportInfo, moduleSpecifierKind: moduleSpecifierKind, moduleSpecifier: moduleSpecifier, usagePosition: usagePosition, } } func getAddToExistingImport( importClauseOrBindingPattern *ast.Node, importKind ImportKind, moduleSpecifier string, moduleSpecifierKind modulespecifiers.ResultKind, addAsTypeOnly AddAsTypeOnly, ) *ImportFix { return &ImportFix{ kind: ImportFixKindAddToExisting, moduleSpecifierKind: moduleSpecifierKind, moduleSpecifier: moduleSpecifier, importClauseOrBindingPattern: importClauseOrBindingPattern, importKind: importKind, addAsTypeOnly: addAsTypeOnly, } } func getNewAddNewImport( moduleSpecifier string, moduleSpecifierKind modulespecifiers.ResultKind, importKind ImportKind, useRequire bool, addAsTypeOnly AddAsTypeOnly, exportInfo *SymbolExportInfo, // !!! | FutureSymbolExportInfo isReExport *bool, qualification *Qualification, ) *ImportFix { return &ImportFix{ kind: ImportFixKindAddNew, isReExport: isReExport, exportInfo: exportInfo, moduleSpecifierKind: modulespecifiers.ResultKindNone, moduleSpecifier: moduleSpecifier, importKind: importKind, addAsTypeOnly: addAsTypeOnly, useRequire: useRequire, } } func getNewPromoteTypeOnlyImport(typeOnlyAliasDeclaration *ast.Declaration) *ImportFix { // !!! function stub return &ImportFix{ kind: ImportFixKindPromoteTypeOnly, // isReExport *bool // exportInfo *SymbolExportInfo // !!! | FutureSymbolExportInfo | undefined // moduleSpecifierKind modulespecifiers.ResultKind // moduleSpecifier string typeOnlyAliasDeclaration: typeOnlyAliasDeclaration, } } /** Information needed to augment an existing import declaration. */ // !!! after full implementation, rename to AddToExistingImportInfo type FixAddToExistingImportInfo struct { declaration *ast.Declaration importKind ImportKind targetFlags ast.SymbolFlags symbol *ast.Symbol } func (info *FixAddToExistingImportInfo) getNewImportFromExistingSpecifier( isValidTypeOnlyUseSite bool, useRequire bool, ch *checker.Checker, compilerOptions *core.CompilerOptions, ) *ImportFix { moduleSpecifier := checker.TryGetModuleSpecifierFromDeclaration(info.declaration) if moduleSpecifier == nil || moduleSpecifier.Text() == "" { return nil } addAsTypeOnly := AddAsTypeOnlyNotAllowed if !useRequire { addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, info.symbol, info.targetFlags, ch, compilerOptions) } return getNewAddNewImport( moduleSpecifier.Text(), modulespecifiers.ResultKindNone, info.importKind, useRequire, addAsTypeOnly, nil, // exportInfo nil, // isReExport nil, // qualification ) }