{"id":37179605,"url":"https://github.com/kucjac/gentools","last_synced_at":"2026-01-14T20:54:04.893Z","repository":{"id":57563685,"uuid":"333510354","full_name":"kucjac/gentools","owner":"kucjac","description":"Package astreflect contains Golang ast based types reflection.","archived":false,"fork":false,"pushed_at":"2022-10-04T09:23:00.000Z","size":329,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-06-21T18:46:44.208Z","etag":null,"topics":["ast","generation","go","golang","reflect"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kucjac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-27T17:42:27.000Z","updated_at":"2023-06-11T03:16:50.000Z","dependencies_parsed_at":"2022-09-16T13:32:56.161Z","dependency_job_id":null,"html_url":"https://github.com/kucjac/gentools","commit_stats":null,"previous_names":["kucjac/astreflect"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/kucjac/gentools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucjac%2Fgentools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucjac%2Fgentools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucjac%2Fgentools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucjac%2Fgentools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kucjac","download_url":"https://codeload.github.com/kucjac/gentools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucjac%2Fgentools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434500,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","generation","go","golang","reflect"],"created_at":"2026-01-14T20:54:04.173Z","updated_at":"2026-01-14T20:54:04.871Z","avatar_url":"https://github.com/kucjac.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Golang Gentools\n\n[![GitHub license](https://img.shields.io/github/license/kucjac/gentools.svg)](https://github.com/kucjac/gentools/blob/master/LICENSE)\n![Workflow Status](https://github.com/kucjac/gentools/actions/workflows/ci.yml/badge.svg)\n[![GoReportCard example](https://goreportcard.com/badge/github.com/kucjac/gentools)](https://goreportcard.com/report/github.com/kucjac/gentools)\n[![GoDoc reference example](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/kucjac/gentools)\n[![GitHub release](https://img.shields.io/github/release/kucjac/gentools.svg)](https://GitHub.com/kucjac/gentools/releases/)\n\n![Gopher](./gopher.png)\n\nPackage `gentools` contains Golang tools used for scanning and parsing golang code.\nIt is based on the golang `ast` and provides simple but very powerful functionality in terms of code scanning.\n\nThe API is expected to be simpler and less verbose than `go/types` package, that looks more like `reflect`.\n\n### Parsing packages\n\nThis package allows reading and scanning the content of go files based on the non-runtime AST definitions.\n\nThe `types.PackageMap` contains context of mapped packages with their structs and dependencies.\n \nThe map could get loaded by using `LoadPackages` function or `types.PackageMap` method with the same name.\nBoth of these loads provided input packages, whereas the method gets only required that doesn't already exist in itself.\n\nExample:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/kucjac/gentools/types\"\n\t\"github.com/kucjac/gentools/parser\"\n)\n\nfunc main() {\n\tpkgs, err := parser.LoadPackages(parser.LoadConfig{\n\t\t// Paths should contain file system paths to related golang directories.\t\t\t\n\t\t// Paths: []string{\"/home/user/golang/src/github.com/kucjac/gentools\", \"./../mypackage\"},\n\t\t\n\t\t// PkgNames should contain full package names to get. It could be set along with the 'Paths' field.\n\t\tPkgNames:   []string{\"github.com/kucjac/gentools\"},\n\t\tBuildFlags: nil,\n\t\tVerbose:    false,\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"Err: Loading packages failed: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n```\n\n\n### Extracting declarations\n\nBased on loaded packages a developer can operate on the types loaded along with these packages.\n\n```go\n// Let's get the types.Type interface and check it's content.\nt, ok := pkgs.TypeOf(\"types.Type\", nil)\nif !ok {\n    fmt.Println(\"Err: getting types.Type failed\")\n    os.Exit(1)\n}\n\n// We can get the name of given type, with or without it's identifier.\nfmt.Println(t.Name(true, \"\")) // types.Type\nfmt.Println(t.Name(false, \"\")) // Type\n\n// We can set up current working package context while getting the name. \n// This way the result should not contain the identifier.\n// The package context could be an identifier or even better full package name.\nfmt.Println(t.Name(true, \"types\")) // Type\n```\n\n\nWhile the packages got loaded not only selected packages were provided but also all dependency imports.\n\n```go\nmutexType, ok := pkgs.TypeOf(\"*sync.Mutex\", nil)\nif !ok {\n\tfmt.Println(\"Err: getting *sync.Mutex failed\")\n\tos.Exit(1)\n}\n\nfmt.Println(mutexType.Name(true, \"\")) // *sync.Mutex\n// We can dereference the pointer, slice, array, channel or wrapper by using 'Elem' method. \nmutexType = mutexType.Elem()\nfmt.Println(mutexType.Name(true, \"\")) // sync.Mutex\n```\n\nThe types allows to easily create and operate on given types with very simple API.\n\n```go\nstructType, ok := pkgs.TypeOf(\"types.Struct\")\nif !ok {\n\tfmt.Println(\"Err: getting types.Struct failed\")\n\tos.Exit(1)\n}\n\n// Let's create a chan of slices of pointers to the given Struct.\nnewType := types.ChanOf(types.RecvOnly, types.SliceOf(types.PointerTo(structType)))\nfmt.Println(sliceType) // chan \u003c-[]*types.Struct\n```\n\nThe package reads all methods and structure fields for loaded types along with the metadata like receiver\ntype (methods) and name, or parameter names.\n\n```go\nsliceType, ok := pkgs.TypeOf(\"types.Array\")\nif !ok {\n\tfmt.Println(\"Err: getting types.Struct failed\")\n\tos.Exit(1)\n}\n\nst := sliceType.(*types.Struct)\nfor i, sField := range st.Fields {\n\tfmt.Printf(\"Field: %d - %s\\t%s\\n\", i, sField.Name, sField.Type)\n}\n\nfor i, method := range st.Methods {\n\tfmt.Printf(\"Method: %d - %s\\n\", i, method)\n}\n```\n\nEach package could also be extracted out of all packages. It is also possible to extract any declaration out of the specific package in a way like:\n```go\nconst typesPkgName = \"github.com/kucjac/gentools/types\"\ntypesPkg, ok := pkgs.PackageByPath(typesPkgName)\nif !ok {\n\tfmt.Printf(\"Err: types package: %s not parsed\\n\", typesPkgName)\n\tos.Exit(1)\n}\n\nfmt.Println(typesPkg.GetPkgPath()) // github.com/kucjac/gentools/types\nfmt.Println(typesPkg.Identifier) // types\n\nparsedPkg, ok := typesPkg.GetType(\"Package\") // This gets parsed types.Package type.\nif !ok {\n\tfmt.Println(\"Err: package types can't get the type 'Package'\")\n\tos.Exit(1)\n}\n\n```\n\n### Comparing types\n\nEach type could be compared to the other in two ways: \n\n#### Compare equality:\n\nTwo types could be compared on their equality by calling the `Equal` method of one type and providing another as an argument.\n\nIf two types are exactly the same then the value would result as true.\n\ni.e.:\n```go\n// Check if the type String is equal to the type Bool \nfmt.Println(types.String.Equal(types.Bool)) // false\n\n// But exactly the same types would give a positive result i.e:\nfmt.Println(types.String.Equal(types.String)) // true\n\n// This also applies to any other type - slice, struct, alias, interface, map, pointer etc i.e.:\nfmt.Println(types.SliceOf(types.String).Equal(types.SliceOf(types.String))) // true\n```\n\nIt is important to see that the aliases would not be equal to the type they point to i.e.:\n\n```go\ntype AliasOfInt int\n\n// Load this package and compare types ...\n\nfmt.Println(aliasOfIntType.Equal(types.Int)) // false\n\n// But if we try to derefence this alias the value would be positive:\n\nfmt.Println(aliasOfIntType.Elem().Equal(types.Int)) // true\n```\n\n#### Compare by Kind\n\nIn some situations if we don't want to check if the types are equal directly, we can compare the kind of the type.\n\nAs an example, we might want to check if the type that we're looking for is a pointer, and if we need to dereference it.\n\nAll dereferences are done by using `Elem()` method, which panics if there is nothing to dereference - you cannot dereference basic types, structs etc.\n\nThese are supported type kinds:\n\n- **KindBool**\n- **KindInt**\n- **KindInt8**\n- **KindInt16**\n- **KindInt32**\n- **KindInt64**\n- **KindUint**\n- **KindUint8**\n- **KindUint16**\n- **KindUint32**\n- **KindUint64**\n- **KindUintptr**\n- **KindFloat32**\n- **KindFloat64**\n- **KindComplex64**\n- **KindComplex128**\n- **KindString**\n- **KindArray**\n- **KindChan**\n- **KindFunc**\n- **KindInterface**\n- **KindMap**\n- **KindPtr**\n- **KindSlice**\n- **KindStruct**\n- **KindUnsafePointer**\n\n\nIn order to compare some types kinds simply use the `Kind` method of the type and compare it  like: \n\n```go\nfmt.Println(type1.Kind() == type2.Kind()) // KindBool == KindBool = true \n```\n\nThis might be super helpful in terms of comparing the kind of aliased types. I.e. if we have alias type mentioned above:\n\n```go\n// AliasOfInt is a type wrapper over the `int` standard type.\ntype AliasOfInt int\n\n// As previously known this would fail\nfmt.Println(aliasOfIntType.Equal(types.Int)) // false\n\n// But we can compare it's kind which would result\nfmt.Println(aliasOfIntType.Kind() == types.KindInt) // true\n```\n\n#### Interface comparison\n\nThis package supports also interfaces comparison. The parser deeply checks all methods and provides a way to check if \nan type (struct, interface) implements also another interface.\n\ni.e.:\n\n```go\nosFile, ok := pkgs.TypeOf(\"*os.File\")\nif !ok {\n\tfmt.Println(\"*os.File not found\")\n\tos.Exit(1)\n}\n\n\nioReader, ok := pkgs.TypeOf(\"io.Reader\")\nif !ok {\n\tfmt.Println(\"io.Reader not found\")\n\tos.Exit(1)\n}\n\n// The function types.Implements allows, checking if a type implements provided interface. \nfmt.Println(types.Implements(osFile, io.Reader.(*types.Interface))) // true\n\nioReadCloser, ok := pkgs.TypeOf(\"io.ReadCloser\")\nif !ok {\n\tfmt.Println(\"io.ReadCloser not found\")\n\tos.Exit(1)\n}\n\n// It could also be an interface - io.ReadCloser implements io.Reader interface.\nfmt.Println(types.Implements(ioReadCloser, io.Reader.(*types.Interface))) // true\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkucjac%2Fgentools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkucjac%2Fgentools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkucjac%2Fgentools/lists"}