{"id":19400857,"url":"https://github.com/nonlogicaldev/gofancyimports","last_synced_at":"2025-07-07T01:38:52.385Z","repository":{"id":48577714,"uuid":"387307477","full_name":"NonLogicalDev/gofancyimports","owner":"NonLogicalDev","description":"📚 A painless way to deterministically format GoLang's imports","archived":false,"fork":false,"pushed_at":"2025-02-14T17:54:38.000Z","size":939,"stargazers_count":16,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-06T08:45:58.556Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NonLogicalDev.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-19T01:40:45.000Z","updated_at":"2025-02-14T08:39:44.000Z","dependencies_parsed_at":"2024-06-21T11:57:25.886Z","dependency_job_id":"a0850b51-cd32-48db-885d-8e89d4c11538","html_url":"https://github.com/NonLogicalDev/gofancyimports","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/NonLogicalDev/gofancyimports","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonLogicalDev%2Fgofancyimports","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonLogicalDev%2Fgofancyimports/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonLogicalDev%2Fgofancyimports/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonLogicalDev%2Fgofancyimports/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NonLogicalDev","download_url":"https://codeload.github.com/NonLogicalDev/gofancyimports/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonLogicalDev%2Fgofancyimports/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263999349,"owners_count":23542022,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-11-10T11:16:08.586Z","updated_at":"2025-07-07T01:38:52.364Z","avatar_url":"https://github.com/NonLogicalDev.png","language":"Go","readme":"# No-Compromise Deterministic GoLang Import Management\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"./assets/gofancyimports_hero.png\" width=\"200\" /\u003e\u003c/p\u003e\n\nA mother of all tools to enforce deterministic order of imports across your golang codebase.\n* ✅ Easy to use, configure or extend\n* ✅ Deterministically orders toughest comment-ridden imports\n* ✅ Respects existing user groupings (pinned by comments)\n* ✅ Handles comments of all varieties gracefully\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\nThis repo is the home for:\n* `pkg/analyzer/autogroupimports` and `pkg/organizer/autogroup` \n\t* ready to use, deterministic, highly configurable, pluggable, import order organizer\n    * based on golang `Analyzer` framework\n* `cmd/gofancyimports fix`\n\t* ready to use cli with full power of `pkg/organizer/autogroup` and same command line interface as `goimports`\n* `gofancyimports`\n  * the lower level library which allows manipulating import groups with ease for implementing your own group and comment aware import fixers\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n \n## `gofancyimports` vs other tools\n\n|                                  | `gofancyimports` | [`goimports`][1] | [`gofumpt`][2] | [`gopls`][3] | [`gci`][4] | [`goimports-reviser`][6] |\n|                               -: | :------------: | :-------: | :-----: | :---: | :-: | :---------------: |\n| deterministic order              | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |\n| graceful comment handling        | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | \n| graceful whitespace handling     | ✅ | ✅ | ✅ | ✅ | ~ | ~ |\n| respect user groupings           | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |\n| fully programmatic configuration | ✅ | ❌ | ❌ | ❌ | ~ | ~ |\n| golang `analysis` integration    | ✅ | ❌ | ❌ | ❓ | ✅ | ✅ |\n| exports framework                | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |\n\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n## Get the ready to use tool:\n\nIf all you need is an import sorting tool that will deterministically fix your import order to a consistent opinionated convention, grab a copy of the `gofancyimports` tool:\n\n```\ngo install github.com/NonLogicalDev/gofancyimports/cmd/gofancyimports@latest\n```\n\n```\n$ gofancyimports fix -h\nFixup single or multiple provided files\n\nUsage:\n  gofancyimports fix [flags]\n\nFlags:\n  -d, --diff                print diff\n      --group-effect        group side effect imports\n      --group-nodot         group no dot imports\n  -h, --help                help for fix\n  -l, --local stringArray   group local imports (comma separated prefixes)\n  -w, --write               write the file back?\n```\n\n## Examples\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth colspan=\"2\"\u003e\u003ccode\u003egofancyimports fix\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003ccode\u003eBefore\u003c/code\u003e\u003c/th\u003e\n\u003cth\u003e\u003ccode\u003eAfter\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"github.com/sanity-io/litter\"\n\t\"flag\"\n)\n\nimport (\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"strconv\"\n\t\"gen/mocks/github.com/go-redis/redis\"\n\t\"github.com/go-redis/redis\"\n\t\"strings\"\n\t\"github.com/NonLogicalDev/gofancyimports\"\n)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"flag\"\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gen/mocks/github.com/go-redis/redis\"\n\t\"github.com/NonLogicalDev/gofancyimports\"\n\t\"github.com/go-redis/redis\"\n\t\"github.com/sanity-io/litter\"\n)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth colspan=\"2\"\u003e\u003ccode\u003egofancyimports fix --group-nodot\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003ccode\u003eBefore\u003c/code\u003e\u003c/th\u003e\n\u003cth\u003e\u003ccode\u003eAfter\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"github.com/sanity-io/litter\"\n\t\"flag\"\n)\n\nimport (\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"strconv\"\n\t\"gen/mocks/github.com/go-redis/redis\"\n\t\"github.com/go-redis/redis\"\n\t\"strings\"\n\t\"github.com/NonLogicalDev/gofancyimports\"\n)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"flag\"\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gen/mocks/github.com/go-redis/redis\"\n\n\t\"github.com/go-redis/redis\"\n\t\"github.com/sanity-io/litter\"\n\t\"github.com/NonLogicalDev/gofancyimports\"\n)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth colspan=\"2\"\u003e\u003ccode\u003egofancyimports fix --group-no-dot --group-effect --local=github.com/NonLogicalDev\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003ccode\u003eBefore\u003c/code\u003e\u003c/th\u003e\n\u003cth\u003e\u003ccode\u003eAfter\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"github.com/sanity-io/litter\"\n\t\"flag\"\n)\n\nimport (\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"strconv\"\n\t\"gen/mocks/github.com/go-redis/redis\"\n\t\"github.com/go-redis/redis\"\n\t\"strings\"\n\t\"github.com/NonLogicalDev/gofancyimports\"\n)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```go\nimport (\n\t\"flag\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gen/mocks/github.com/go-redis/redis\"\n\n\t\"github.com/go-redis/redis\"\n\t\"github.com/sanity-io/litter\"\n\n\t\"github.com/NonLogicalDev/gofancyimports\"\n\n\t_ \"net/http/pprof\"\n)\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n# 🎓 Extending or implementing your own import fixer\n\n## Background:\n\nThere are plenty of tools for formatting GoLang. Most of them do a fairly good job at\ntidying up imports.  However they tend to not give a lot of power for deterministically\nsetting the order, or suffer from issues around dealing with comments.\n\nThe world of Go Imports formatting divides into three common approaches:\n\n1. Trust the programmer's groupings, and don't muck around with them, only sort within groups:\n\t* [`go imports`][1]\n2. Don't trust the programmer's grouping and impose a set of opinionated restrictive rules on how imports should be grouped.\n\t* [`go fumpt`][2] / [`gopls`][3]\n3. Give a little bit of control via CLI parameters but not export the framework to build custom formatter.\n\t* [`gci`][4] / [`goimports-reviser`][6]\n\nIf your organization or project happens to use a convention that does not fit within the\ngroup 2, and you wish to modify an existing tool like fumpt, it ends up being rather\ndifficult endeavor as these tools have not been designed with simple extensiblity in mind.\nThis project stems from a wish to make programmaticaly defining rules for organizing\nimports simple and composable.\n\nLucky for us Go is blessed with a very well documented parser and AST implementation,\nhowever one of its biggest shortcomings is dealing with comments, and whitespace,\nespecially around imports, because beyond the bare basics it ALL all about managing\ncomments and whitespace.  With advent of tools like [`go analysis`][3] which are very\nflexible about inspecting and modifying code, a compatible tool for programmatically\nworking with imports groupings is sorely needed to provide a simple way of implementing an\norganization wide import style to avoid editor configurations fighting each other. \n\n\n## Solution `gofancyimports`\n\nA tool that exposes import groups as a concept to the rule writer, and allow them to\nreorder, merge and split them deterministically, taking care of everything else.\n\nThe biggest selling point of this library is that you don't have to become an AST expert\nto write an import transform using this library, everything is handled sensibly and\nautomatically, you just provide a function that takes existing import groupings (nicely\nabstracted) and transform it into a list of groupings you desire. All comments will be\nhoisted and adjusted for you.\n\nThis framework takes away the difficulty from dealing with floating comments, and\nwhitespace between import spec groupings, by exposing import declarations and groupings as\nsimple structs that you can freely modify.  All of the complexity of rebuilding the\nimports AST to your spec represented by those structs is taken care of.\n\nThis framework can understand import clauses like this (See `Fig 1`). For example: all comments in the\nbelow figure are structurally parsed and when transformed are properly positioned, no\nmatter how you reorder the import groups, all complexity of recomputing AST offsets is\ncompletely abstracted away.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eFig 1\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\n```go\npackage example\n\n// [Import Decl Leading Comment: leading comment (not included as it is located prior to import group block)]\n\nimport \"singleImport\" // [Import Spec Comment: singleImport]\n\n// [Import Decl Detached Comment: hoisted to Import Decl that follows]\n\n// [Import Decl Doc Comment: for entire import block]\n/*\n\tMultiline comments are understood and handled properly (import level).\n*/\nimport (\n\t\"pkg1\" // [Import Spec Comment: pkg1]\n\t\"pkg2\"\n\n\t// [Import Decl Detached comment 1: unattached to Import Specs, but exposed in enclosing Import Decl]\n\n\t// [Import Spec Group Doc Comment: (pkg3, pkg4)]\n\t/*\n\t\tMultiline comments are understood and handled properly (spec level).\n\t*/\n\t\"pkg3\"\n\t\"pkg4\"\n\n\t// [Import Decl Detached comment 2: unattached to Import Specs, but exposed in enclosing Import Decl]\n)\n\n// [Import Decl Trailing comment: comment following the import specs]\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eFig 1.1\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003ccode\u003egofancyimports debug\u003c/code\u003e output showing parsed import section\n\u003c/summary\u003e\n\n```\n[\n  {\n    \"CommentDoc\": null,\n    \"CommentLeading\": null,\n    \"CommentDetached\": null,\n    \"Groups\": [\n      {\n        \"CommentDoc\": null,\n        \"Specs\": [\n          [\n            \"\\\"singleImport\\\"// [Import Spec Comment: singleImport]\",\n            \"\"\n          ]\n        ]\n      }\n    ]\n  },\n  {\n    \"CommentDoc\": {\n      \"CommentGroup\": [\n        {\n          \"Lines\": [\n            \"// [Import Decl Doc Comment: for entire import block]\"\n          ]\n        },\n        {\n          \"Lines\": [\n            \"/*\",\n            \"\\tMultiline comments are understood and handled properly (import level).\",\n            \"*/\"\n          ]\n        }\n      ]\n    },\n    \"CommentLeading\": [\n      {\n        \"CommentGroup\": [\n          {\n            \"Lines\": [\n              \"// [Import Decl Detached Comment: hoisted to Import Decl that follows]\"\n            ]\n          }\n        ]\n      }\n    ],\n    \"CommentDetached\": [\n      {\n        \"CommentGroup\": [\n          {\n            \"Lines\": [\n              \"// [Import Decl Detached comment 1: unattached to Import Specs, but exposed in enclosing Import Decl]\"\n            ]\n          }\n        ]\n      },\n      {\n        \"CommentGroup\": [\n          {\n            \"Lines\": [\n              \"// [Import Decl Detached comment 2: unattached to Import Specs, but exposed in enclosing Import Decl]\"\n            ]\n          }\n        ]\n      }\n    ],\n    \"Groups\": [\n      {\n        \"CommentDoc\": null,\n        \"Specs\": [\n          [\n            \"\\\"pkg1\\\"// [Import Spec Comment: pkg1]\",\n            \"\"\n          ],\n          [\n            \"\\\"pkg2\\\"\"\n          ]\n        ]\n      },\n      {\n        \"CommentDoc\": {\n          \"CommentGroup\": [\n            {\n              \"Lines\": [\n                \"// [Import Spec Group Doc Comment: (pkg3, pkg4)]\"\n              ]\n            },\n            {\n              \"Lines\": [\n                \"/*\",\n                \"\\t\\tMultiline comments are understood and handled properly (spec level).\",\n                \"\\t*/\"\n              ]\n            }\n          ]\n        },\n        \"Specs\": [\n          [\n            \"\\\"pkg3\\\"\"\n          ],\n          [\n            \"\\\"pkg4\\\"\"\n          ]\n        ]\n      }\n    ]\n  }\n]\n\n```\n\n\u003c/details\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThis package mainly exposes the following high level interface (See `Fig 2`). The\nimplementation of a custom import fixer boils down to implementation of a simple function\nthat transforms one list of `[]ImportDelaration` that was parsed from file to another list\nof `[]ImportDelaration`.\n\nYou can reorder add or remove entries from those `ImportDeclarations`. \nNo comments will be lost and all new and existing comments will be magically and appropriately placed.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eFig 2\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\n// imports.go\n// ----------------------------------------------------------------------\n\n// WithTransform allows overriding a custom import group transform.\n// This is the main extension point for this library. By setting a custom\n// function as the transform it is very simple to take complete control over the\n// import ordering.\nfunc WithTransform(transform types.ImportTransform) Option // ...\n\n// RewriteImportsSource takes a filename and source and rewrite options and applies import transforms to the file.\n//\n// Consult the [WithTransform] function for a complete usage example.\nfunc RewriteImportsSource(filename string, src []byte, opts ...Option) ([]byte, error) // ...\n\n// RewriteImportsAST is a lower level function that takes a filename and source and returns\n// an analysis.TextEdit snippet containing proposed fixes for out of the box integration\n// with analysis libraries.\n//\n// In most cases [RewriteImportsSource] is a much more ergonomic batteries-included alternative.\n//\n// Contract: This functions will only ever return a single text edit.\n//\n// Consult the [WithTransform] function for a complete usage example.\nfunc RewriteImportsAST(fset *token.FileSet, node *ast.File, src []byte, opts ...Option) ([]*analysis.TextEdit, error)\n\n// pkg/types/types.go\n// ----------------------------------------------------------------------\n\n// ImportTransform is a function that allows reordering merging and splitting\n// existing ImportDeclaration-s obtained from source.\ntype ImportTransform func(decls []ImportDeclaration) []ImportDeclaration\n\n// ImportDeclaration represents a single import block. (i.e. the contents of the `import` statement)\ntype ImportDeclaration struct {\n\t// LeadingComments comments that are floating above this declaration,\n\t// in the middle of import blocks.\n\tLeadingComments []*ast.CommentGroup\n\n\t// DetachedComments are comments that are floating inside this declaration\n\t// unattached to specs (typically after the last import spec in a group).\n\tDetachedComments []*ast.CommentGroup\n\n\t// Doc is the doc comment for this import declaration.\n\tDoc *ast.CommentGroup\n\n\t// ImportGroups contains the list of underlying ast.ImportSpec-s.\n\tImportGroups []ImportGroup\n}\n\n// ImportGroup maps to set of consecutive import specs delimited by\n// whitespace and potentially having a doc comment.\n//\n// This type is the powerhouse of this package, allowing easy operation\n// on sets of imports, delimited by whitespace.\n//\n// Contained within an ImportDeclaration.\ntype ImportGroup struct {\n\tDoc   *ast.CommentGroup\n\tSpecs []*ast.ImportSpec\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can see the ease of use of this by having a look at:\n* [gofancyimports/main.go](./cmd/gofancyimports/main.go)\n  * Implementation of CLI that is using configurable autogroup transform\n* [pkg/organizer/autogroup](./pkg/organizer/autogroup/organizer.go)\n  * Implementation of Autogroup transform that is implemented using `gofancyimports` framework\n\n# Appendix\n\n## Appendix (Go Analysis Integration):\n\nGood example of how easy using `go analysis` is:\n* https://arslan.io/2020/07/07/using-go-analysis-to-fix-your-source-code/\n\n## Appendix (AST Comments)\n\nThe difficulty of working with comments in Go AST mainly stems from the fact that\nComments are do not quite behave like other AST nodes.\n\nFirstly they are not part of the tree unless they are referenced by another AST node as\neither Doc or Line End comment.\n\nAnd secondly they are very rigidly tied to the Byte offsets of corresponding files,\nmeaning making changes to them or AST nodes to which they are attached requires\nrecalculating their offset positions manually.\n\n## Appendix (Misc)\n\n* https://github.com/golang/tools/blob/6e9046bfcd34178dc116189817430a2ad1ee7b43/internal/imports/sortimports.go#L63\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n[1]: https://pkg.go.dev/golang.org/x/tools/cmd/goimports\n[2]: https://github.com/mvdan/gofumpt\n[3]: https://github.com/golang/tools/tree/master/gopls\n[4]: https://github.com/daixiang0/gci\n[5]: https://pkg.go.dev/golang.org/x/tools/go/analysis\n[6]: https://github.com/incu6us/goimports-reviser\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnonlogicaldev%2Fgofancyimports","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnonlogicaldev%2Fgofancyimports","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnonlogicaldev%2Fgofancyimports/lists"}