Skip to content

Commit

Permalink
Enhancements: search imports sequencely, till find the type. (#1374)
Browse files Browse the repository at this point in the history
* Enhancements: search imports sequencely, till find the type.
consider every import mode ,such as alias,underline, dot.
a model imported from an external by mode dot.
  • Loading branch information
sdghchj committed Nov 2, 2022
1 parent 07690e9 commit eaed517
Show file tree
Hide file tree
Showing 19 changed files with 751 additions and 321 deletions.
3 changes: 2 additions & 1 deletion generics_test.go
Expand Up @@ -106,11 +106,12 @@ func TestParseGenericsNames(t *testing.T) {
func TestParseGenericsPackageAlias(t *testing.T) {
t.Parallel()

searchDir := "testdata/generics_package_alias"
searchDir := "testdata/generics_package_alias/internal"
expected, err := os.ReadFile(filepath.Join(searchDir, "expected.json"))
assert.NoError(t, err)

p := New()
p.ParseDependency = true
err = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)
assert.NoError(t, err)
b, err := json.MarshalIndent(p.swagger, "", " ")
Expand Down
142 changes: 65 additions & 77 deletions packages.go
Expand Up @@ -287,76 +287,93 @@ func (pkgDefs *PackagesDefinitions) loadExternalPackage(importPath string) error
// findPackagePathFromImports finds out the package path of a package via ranging imports of an ast.File
// @pkg the name of the target package
// @file current ast.File in which to search imports
// @fuzzy search for the package path that the last part matches the @pkg if true
// @return the package path of a package of @pkg.
func (pkgDefs *PackagesDefinitions) findPackagePathFromImports(pkg string, file *ast.File, fuzzy bool) string {
// @return the package paths of a package of @pkg.
func (pkgDefs *PackagesDefinitions) findPackagePathFromImports(pkg string, file *ast.File) (matchedPkgPaths, externalPkgPaths []string) {
if file == nil {
return ""
return
}

if strings.ContainsRune(pkg, '.') {
pkg = strings.Split(pkg, ".")[0]
}

hasAnonymousPkg := false

matchLastPathPart := func(pkgPath string) bool {
paths := strings.Split(pkgPath, "/")

return paths[len(paths)-1] == pkg
}

// prior to match named package
for _, imp := range file.Imports {
path := strings.Trim(imp.Path.Value, `"`)
if imp.Name != nil {
if imp.Name.Name == pkg {
return strings.Trim(imp.Path.Value, `"`)
// if name match, break loop and return
_, ok := pkgDefs.packages[path]
if ok {
matchedPkgPaths = []string{path}
externalPkgPaths = nil
} else {
externalPkgPaths = []string{path}
matchedPkgPaths = nil
}
break
} else if imp.Name.Name == "_" && len(pkg) > 0 {
//for unused types
pd, ok := pkgDefs.packages[path]
if ok {
if pd.Name == pkg {
matchedPkgPaths = append(matchedPkgPaths, path)
}
} else if matchLastPathPart(path) {
externalPkgPaths = append(externalPkgPaths, path)
}
} else if imp.Name.Name == "." && len(pkg) == 0 {
_, ok := pkgDefs.packages[path]
if ok {
matchedPkgPaths = append(matchedPkgPaths, path)
} else if len(pkg) == 0 || matchLastPathPart(path) {
externalPkgPaths = append(externalPkgPaths, path)
}
}

if imp.Name.Name == "_" {
hasAnonymousPkg = true
} else if pkgDefs.packages != nil && len(pkg) > 0 {
pd, ok := pkgDefs.packages[path]
if ok {
if pd.Name == pkg {
matchedPkgPaths = append(matchedPkgPaths, path)
}
} else if matchLastPathPart(path) {
externalPkgPaths = append(externalPkgPaths, path)
}

continue
}
}

if pkgDefs.packages != nil {
path := strings.Trim(imp.Path.Value, `"`)
if fuzzy {
if matchLastPathPart(path) {
return path
}
if len(pkg) == 0 || file.Name.Name == pkg {
matchedPkgPaths = append(matchedPkgPaths, pkgDefs.files[file].PackagePath)
}

continue
}
return
}

pd, ok := pkgDefs.packages[path]
if ok && pd.Name == pkg {
return path
}
func (pkgDefs *PackagesDefinitions) findTypeSpecFromPackagePaths(matchedPkgPaths, externalPkgPaths []string, name string, parseDependency bool) (typeDef *TypeSpecDef) {
for _, pkgPath := range matchedPkgPaths {
typeDef = pkgDefs.findTypeSpec(pkgPath, name)
if typeDef != nil {
return typeDef
}
}

// match unnamed package
if hasAnonymousPkg && pkgDefs.packages != nil {
for _, imp := range file.Imports {
if imp.Name == nil {
continue
}
if imp.Name.Name == "_" {
path := strings.Trim(imp.Path.Value, `"`)
if fuzzy {
if matchLastPathPart(path) {
return path
}
} else if pd, ok := pkgDefs.packages[path]; ok && pd.Name == pkg {
return path
if parseDependency {
for _, pkgPath := range externalPkgPaths {
if err := pkgDefs.loadExternalPackage(pkgPath); err == nil {
typeDef = pkgDefs.findTypeSpec(pkgPath, name)
if typeDef != nil {
return typeDef
}
}
}
}

return ""
return typeDef
}

// FindTypeSpec finds out TypeSpecDef of a type by typeName
Expand All @@ -379,23 +396,8 @@ func (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File
return typeDef
}

pkgPath := pkgDefs.findPackagePathFromImports(parts[0], file, false)
if len(pkgPath) == 0 {
// check if the current package
if parts[0] == file.Name.Name {
pkgPath = pkgDefs.files[file].PackagePath
} else if parseDependency {
// take it as an external package, needs to be loaded
if pkgPath = pkgDefs.findPackagePathFromImports(parts[0], file, true); len(pkgPath) > 0 {
if err := pkgDefs.loadExternalPackage(pkgPath); err != nil {
return nil
}
}
}
}

typeDef = pkgDefs.findTypeSpec(pkgPath, parts[1])

pkgPaths, externalPkgPaths := pkgDefs.findPackagePathFromImports(parts[0], file)
typeDef = pkgDefs.findTypeSpecFromPackagePaths(pkgPaths, externalPkgPaths, parts[1], parseDependency)
return pkgDefs.parametrizeGenericType(file, typeDef, typeName, parseDependency)
}

Expand All @@ -410,25 +412,11 @@ func (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File
return typeDef
}

typeDef = func() *TypeSpecDef {
name := parts[0]
typeDef, ok := pkgDefs.uniqueDefinitions[fullTypeName(file.Name.Name, name)]
if ok {
return typeDef
}
typeDef = pkgDefs.findTypeSpec(pkgDefs.files[file].PackagePath, name)
if typeDef != nil {
return typeDef
}
for _, imp := range file.Imports {
if imp.Name != nil && imp.Name.Name == "." {
typeDef = pkgDefs.findTypeSpec(strings.Trim(imp.Path.Value, `"`), name)
if typeDef != nil {
break
}
}
}
return typeDef
}()
name := parts[0]
typeDef, ok = pkgDefs.uniqueDefinitions[fullTypeName(file.Name.Name, name)]
if !ok {
pkgPaths, externalPkgPaths := pkgDefs.findPackagePathFromImports("", file)
typeDef = pkgDefs.findTypeSpecFromPackagePaths(pkgPaths, externalPkgPaths, name, parseDependency)
}
return pkgDefs.parametrizeGenericType(file, typeDef, typeName, parseDependency)
}

0 comments on commit eaed517

Please sign in to comment.