{"id":13412957,"url":"https://github.com/switchupcb/copygen","last_synced_at":"2025-04-09T06:12:40.820Z","repository":{"id":37633761,"uuid":"408656832","full_name":"switchupcb/copygen","owner":"switchupcb","description":"Go generator to copy values from type to type and fields from struct to struct (copier without reflection). Generate any code based on types.","archived":false,"fork":false,"pushed_at":"2024-03-10T21:16:42.000Z","size":439,"stargazers_count":339,"open_issues_count":7,"forks_count":22,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-07-31T20:51:43.539Z","etag":null,"topics":["code-generation","code-generator","copy","generator","go","golang"],"latest_commit_sha":null,"homepage":"https://switchupcb.com/copygen-license-exception/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/switchupcb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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-09-21T01:51:04.000Z","updated_at":"2024-07-31T20:51:43.540Z","dependencies_parsed_at":"2024-01-08T15:02:58.446Z","dependency_job_id":"9301625e-4822-43b3-9418-0676661f553c","html_url":"https://github.com/switchupcb/copygen","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/switchupcb%2Fcopygen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/switchupcb%2Fcopygen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/switchupcb%2Fcopygen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/switchupcb%2Fcopygen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/switchupcb","download_url":"https://codeload.github.com/switchupcb/copygen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987285,"owners_count":21028895,"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":["code-generation","code-generator","copy","generator","go","golang"],"created_at":"2024-07-30T20:01:31.586Z","updated_at":"2025-04-09T06:12:40.801Z","avatar_url":"https://github.com/switchupcb.png","language":"Go","readme":"\u003cbr\u003e\n\n[\u003cimg id=\"copygen\" alt=\"Copygen Logo\" src=\".github/logo.svg\" width=\"512\"/\u003e](https://github.com/switchupcb/copygen#copygen)\n\n---\n\n[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge\u0026logo=appveyor\u0026logo=appveyor)](https://pkg.go.dev/github.com/switchupcb/copygen)\n[![License](https://img.shields.io/github/license/switchupcb/copygen.svg?style=for-the-badge)](https://github.com/switchupcb/copygen/blob/main/LICENSE)\n[\u003cimg id=\"awesomego\" alt=\"Mentioned in Awesome Go\" src=\"https://awesome.re/mentioned-badge-flat.svg\" height=\"28\"/\u003e](https://github.com/avelino/awesome-go#generators)\n\nCopygen saves you from losing time writing repetitive code with a type-based code generator.\n\n## What is Copygen?\n\nCopygen is a command-line and programmatic **code generator** that generates custom type-based code, including type-to-type and field-to-field code without adding any reflection or dependencies to your project. Manual-copy code generated by Copygen is [**391x faster**](https://github.com/gotidy/copy#benchmark) than **jinzhu/copier** and adds no allocation to your program.\n\n_Copygen supports **every** Go type including `basic`, `array`, `slice`, `map`, `chan`, `interface`, and `func` types._\n\n## Table of Contents\n\n| Topic                            | Categories                                                                                                                                    |\n| :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |\n| [Usage](#how-do-you-use-copygen) | [Types](#step-1-define-go-types), [Setup](#step-2-configure-the-setup-files), [Command Line](#step-3-use-the-command-line), [Output](#output) |\n| [Customization](#customization)  | [Custom Objects](#custom-objects), [Templates](#templates)                                                                                    |\n| [Matcher](#matcher)              | [Automatch](#automatch), [Manual](#manual), [Depth](#depth)                                                                                   |\n| [Usecases](#usecase)             | [When to Use](#when-to-use-copygen), [Custom Generation](#custom-generation)                                                                  |\n| [License](#what-is-the-license)  | [What can I do?](#what-can-you-do-with-this-license), [License Exception](#what-is-a-license-exception)                                       |\n\n## How do you use Copygen?\n\nEach example has a **README**.\n\n| Example                          | Description                              |\n| :------------------------------- | :--------------------------------------- |\n| main                             | The default example.                     |\n| [basic](examples/basic/)         | Matches a `basic` type to a field.       |\n| [automatch](examples/automatch/) | Uses the automatch matcher with depth.   |\n| [map](examples/map/)             | Uses the manual map matcher.             |\n| [tag](examples/tag/)             | Uses the manual tag matcher.             |\n| [cast](examples/cast/)           | Uses the cast modifier.                  |\n| deepcopy _(Roadmap)_             | Uses the deepcopy option.                |\n| [error](examples/error/)         | Uses `.go` templates to return an error. |\n| [tmpl](examples/tmpl/)           | Uses `.tmpl` templates.                  |\n| [program](examples/program/)     | Uses Copygen programmatically.           |\n\n_*[`multi`](examples/_tests/multi/setup/setup.go) tests every type._\n\nThis [example](examples/main/) uses three type-structs to generate the `ModelsToDomain()` function using a Command Line Interface.\n\n### Step 1. Define Go Types\n\nGo types are defined in a file.\n\n`./domain/domain.go`\n\n```go\n// Package domain contains business logic models.\npackage domain\n\n// Account represents a user account.\ntype Account struct {\n\tID     int\n\tUserID string\n\tName   string\n\tOther  string // The other field is not used.\n}\n```\n\n`./models/model.go`\n\n```go\n// Package models contains data storage models (i.e database).\npackage models\n\n// Account represents the data model for account.\ntype Account struct {\n\tID       int\n\tName     string\n\tPassword string\n\tEmail    string\n}\n\n// A User represents the data model for a user.\ntype User struct {\n\tUserID   int\n\tName     string\n\tUserData string\n}\n```\n\nThe `models.Account` and `models.User` fields will be copied to `domain.Account` fields.\n\n### Step 2. Configure the setup files\n\nYou set up Copygen with a `YML` and `GO` file.\n\n#### setup.yml\n\n```yml\n# Define where the code is generated.\ngenerated:\n  setup: ./setup.go\n  output: ../copygen.go\n\n  # Define the optional custom templates used to generate the file (.go, .tmpl supported).\n  # template: ./generate.go\n\n# Define custom options (which are passed to generator options) for customization.\ncustom:\n  option: The possibilities are endless.\n```\n\n#### setup.go\n\nDefine a `type Copygen interface` in the specified setup file.\n\nIn each function, specify _the types you want to copy from_ as parameters, and _the types you want to copy to_ as return values.\n\n_This interface is inspired by **goverter**._\n\n```go\n/* Specify the name of the generated file's package. */\npackage copygen\n\n/* Copygen defines the functions that are generated. */\ntype Copygen interface {\n  // custom see table below for options\n  ModelsToDomain(*models.Account, *models.User) *domain.Account\n}\n```\n\n_Copygen uses no allocation **with pointers** because Go is pass-by-value. So, using a pointer results in the object's fields being assigned directly as opposed to a copy of the object's fields._\n\n#### options\n\nUse comments to specify options for Copygen functions: Do **NOT** add empty lines between comments that pertain to one function.\n\n**Options are evaluated in order of declaration.**\n\n| Option              | Use                                                              | Description                                                                                                                                                                        | Example                                                                      |\n| :------------------ | :--------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |\n| `automatch field`   | Use the automatcher selectively or with `map` and `tag` options. | Using `map` or `tag` disables the default automatcher. \u003cbr /\u003e Enable it again using `automatch` with _regex_.                                                                      | `automatch package.Type.Field` \u003cbr /\u003e `automatch models.User.*`              |\n| `map from to`       | Map fields manually.                                             | `map` fields to and from each other. \u003cbr /\u003e Regex is supported for from-fields.                                                                                                    | `map .* package.Type.Field` \u003cbr /\u003e `map models.Account.ID domain.Account.ID` |\n| `tag field key`     | Map fields manually using struct tags.                           | Use `tag` with _regex_ and a tag key.                                                                                                                                              | `tag package.Type.Field key` \u003cbr /\u003e `tag .* api` _(all fields)_              |\n| `depth field level` | Use a specific field depth.                                      | Copygen uses full-field [depth](#depth) by default. \u003cbr /\u003e Override this using `depth` with _regex_ and a [depth-level](#depth) integer.                                           | `depth .* 2` \u003cbr /\u003e `depth models.Account.* 1`                               |\n| `deepcopy field`    | Deepcopy from-fields.                                            | Copygen shallow copies fields by default. \u003cbr /\u003e Override this using `deepcopy` with _regex_. \u003cbr /\u003e For more info, view [Shallow Copy vs. Deep Copy](#shallow-copy-vs-deep-copy). | `deepcopy package.Type.Field` \u003cbr /\u003e `deepcopy .*` _(all fields)_            |\n| `custom option`     | Specify custom function options.                                 | Use custom options with [templates](#templates). \u003cbr /\u003e Returns `map[string][]string` _(trim-spaced)_.                                                                             | `ignore true` \u003cbr /\u003e `swap false`                                            |\n\n_[View a reference on Regex.](https://cheatography.com/davechild/cheat-sheets/regular-expressions/)_\n\nA matching option _(e.g. `map`, `automatch`, `tag`)_ determines whether the field is matched to another field, but a modifying option _(e.g. `convert`, `cast`)_ is only applied when a field is matched.\n\n#### Convert\n\nUse the `convert function field` option to control how a type or field is copied within a function when the field is matched.\n\n\n```go\n/* Define the function and field this converter is applied to using regex. */\n// convert .* models.User.UserID\n// Itoa converts an integer to an ascii value.\nfunc Itoa(i int) string {\n\treturn c.Itoa(i)\n}\n```\n\n_This example converts the `models.User.UserID` value using `Itoa` within all functions (`.*`) when the `models.User.UserID` field is matched._\n\n#### Cast\n\nUse the `setup.yml` `matcher: cast` generator option to enable automatic casting when a field is matched.\n\nUse the `setup.go` `cast from to modifier` option to perform direct type assertion, conversion, expressions, function usage, and property usage with a matched field. \n\nFor more information, read the [`cast` example](/examples/cast/).\n\n### Step 3. Use the Command Line\n\nInstall the command line utility: Copygen.\n\n```\ngo install github.com/switchupcb/copygen@latest\n```\n\nInstall a specific version by specifying a branch.\n```\ngo install github.com/switchupcb/copygen@main\n```\n\nInstall a specific version by specifying a tag.\n```\ngo install github.com/switchupcb/copygen@v0.4.1\n```\n\nRun the executable with given options.\n\n```bash\ncopygen -yml path/to/yml\n```\n\n_The path to the YML file must be specified in reference to the current working directory._\n\n### Output\n\nThis example outputs a `copygen.go` file with the specified imports and functions.\n\n```go\n// Code generated by github.com/switchupcb/copygen\n// DO NOT EDIT.\n\n// Package copygen contains the setup information for copygen generated code.\npackage copygen\n\nimport (\n\tc \"strconv\"\n\n\t\"github.com/switchupcb/copygen/examples/main/domain\"\n\t\"github.com/switchupcb/copygen/examples/main/models\"\n)\n\n// Itoa converts an integer to an ascii value.\nfunc Itoa(i int) string {\n\treturn c.Itoa(i)\n}\n\n// ModelsToDomain copies a *models.Account, *models.User to a *domain.Account.\nfunc ModelsToDomain(tA *domain.Account, fA *models.Account, fU *models.User) {\n\t// *domain.Account fields\n\ttA.ID = fA.ID\n\ttA.UserID = Itoa(fU.UserID)\n\ttA.Name = fA.Name\n}\n```\n\n## Customization\n\nCopygen's method of input and output lets you generate code that isn't limited to copying fields.\n\n### Custom Objects\n\nCustom types external to your application can be defined in the setup file (`.go`): When an output file is generated, all types _(structs, interfaces, funcs)_ defined in the setup file (`.go`) are copied **EXCEPT** the `type Copygen interface`.\n\n```go\ntype DataTransferObject struct {\n  // ...\n}\n\ntype Model interface {\n  // ...\n}\n\nfunc New() {\n  // ...\n}\n```\n\n### Shallow Copy vs. Deep Copy\n\nThe library generates [shallow copy](https://en.m.wikipedia.org/wiki/Object_copying#Shallow_copy) functions by default. \n\nDo you need to deepcopy instead? Use `new()` within a `convert` or `cast` function **or** use a customized generator template.\n\n### Templates\n\nCopygen supports three methods of code generation: `.go`, `.tmpl`, and `programmatic`. \n\nYou can view the [models.Generator](cli/models/generator.go) type for context on the parameters passed to each function.\n- Generator options are parsed from the YML configuration file.\n- Function options are parsed from `custom` options.\n- Any other option represents a `FieldOption`.\n\n#### .go\n\nUse `.go` files to customize the code generation algorithm: The `copygen` generator uses the [`package template Generate(*models.Generator) (string, error)`](cli/generator/template/generate.go) to generate code. So, **this function is required** for your `.go` templates to work. \n\nThe [error example](examples/error/) modifies the configuration file (`.yml`) to use **custom `.go` template functions** that `return error`. The [`template/generate.go`](/cli//generator/template/generate.go) file provides the default code generation algorithm for generating code.\n\n_Use of non-extracted Go Module Imports in [`generate.go` template files](cli/generator/template/generate.go) are unsupported at the current time._\n\n#### .tmpl\n\nUse `.tmpl` _([`text/templates`](https://pkg.go.dev/text/template))_ to customize the code generation algorithm. The [template example](examples/tmpl/) uses a [`.tmpl`](/examples/tmpl/template/generate.tmpl) file to generate code.\n\n#### programmatic\n\nUse `copygen` as a third-party module in your application. For more information, read the [program example](/examples/program/README.md).\n\n## Matcher\n\nCopygen provides two methods of field-matching: `automatch` and `manual`.\n\n_You can disable the matcher using the `matcher: skip: true` option in the setup file._\n\n### Automatch\n\nCopygen automatically matches the function's fields by field name and definition when a [matching option _(`automatch`,`map`,`tag`)_](#options) isn't specified on a function.\n- Automatch matches one from-field to many to-fields\n- **Automatch supports field-depth** (when fields contain fields) **and recursive types** (when the field contains itself).\n- Automatch loads types from Go modules _(in the `GOPATH`)_: Confirm your Go modules are up-to-date using `go get -u \u003cinsert/module/import/path\u003e`.\n\n### Manual\n\nUsing the `map` or `tag` option disables the automatcher, which lets you manually match fields. In order to re-enable the automatcher, use the `automatch` option. \n\nOptions are evaluated in order of declaration, so using `automatch .*` **after** declaring `map` and `tag` options is an easy way to re-enable the _automatcher_ for remaining fields.\n\n#### Depth\n\nThe automatcher uses a field-based depth system where a field with a depth-level of 0 only matches itself. This system lets you specify the depth-level for specific types and fields. Increasing the depth-level lets the field's sub-fields at a specified depth-level be matched.\n\n```go\n// Depth-level in relation to the first-level field (0).\ntype Account\n  // 1\n  ID      int\n  Name    string\n  Email   string\n  Basic   domain.T // int\n  User    domain.DomainUser\n              // 2\n              UserID   string\n              Name     string\n              UserData map[string]interface{}\n  // 1\n  Log     log.Logger\n              // 2\n              mu      sync.Mutex\n                          // 3\n                          state   int32\n                          sema    uint32\n              // 2\n              prefix  string\n              flag    int\n              out     io.Writer\n                          // 3\n                          Write   func(p []byte) (n int, err error)\n              buf     []byte\n```\n\n## Usecase\n\n### When to Use Copygen\n\nCopygen's default purpose is to save you time by generating code to map objects together.\n\n### Why would you do that?\n\nYou generate code to map objects together when your program contains multiple models types (e.g., `domain`, `database`), which improves feature development speed without affecting performance.\n\n_Here is an example._\n\nSuppose a program maintains two types of models for feature development.\n- The **domain model** is a human-optimized definition of the business logic, and is used by a human to develop business logic. For example, an `account` model which is defined for use by a human.\n- The **data model** is a machine-optimized definition of the business logic, and is used by a machine to execute business logic efficiently. For example, a database model of an `account` which defines `username`, `profile_picture`, and other account related data in separate models for database efficiency.\n \nThese models are created because the ideal method of data storage is not the ideal domain model. However, you must map these models together to exchange information from your data model to your domain model and vice-versa.\n\n_Here is an example of how Copygen uses this development pattern._\n- The [domain models of Copygen](cli/models/) focus on field relations and manipulation as understood by a human.\n- The [data models of Copygen](cli/config/models.go) are located in its configuration loader and Go type `ast` structs.\n- The \"business logic\" of Copygen is defined in the `parser`, `matcher`, and `generator`, which use the `domain` models of Copygen to generate code instead of underlying `ast` data structs.\n\n### Custom Generation\n\nCopygen's customizability with templates lets you generate any code **based on types** _(and their respective fields, tags, etc)_. \n\n| Example | Description                                                                             |\n| :------ | :-------------------------------------------------------------------------------------- |\n| Repogen | Generate a Business-Logic Repository package based on a Data Access Object (DAO) model. |\n| Wrapper | Generate functions for requests using an API resource and request object model.         |\n\n_Check out more usecases in real-world examples using [Copygen Usecases](https://github.com/switchupcb/copygen/discussions/categories/usecases)._\n\n## What is the License?\n\nCopygen uses a [AGPLv3 License](https://www.gnu.org/licenses/agpl-3.0.en.html).\n\nAn exception is provided for template and example files, which are licensed under the [MIT License](cli/generator/template/LICENSE.md).\n\n### What can you do with this license?\n\n**Code generated by Copygen can be used without restriction (including proprietary and commercial usage)** since generated code is not considered a derivative work. However, **modifications** to the _Copygen Software Source Code_ or implementing Copygen in a larger work **programmatically** requires you to [adhere to the AGPLv3 License](https://www.gnu.org/licenses/gpl-faq.html). \n\n_These restrictions do **NOT** apply to template or example files, as long as those files don't generate Copygen itself._\n\n### What is a license exception?\n\nA license exception lets you modify and use Copygen programmatically **without restriction**. \n\nYou can receive a license exception for Copygen by contacting SwitchUpCB using the [Copygen License Exception Inquiry Form](https://switchupcb.com/copygen-license-exception/).\n\n## Contributing\n\nYou can contribute to this repository by viewing the [Project Structure, Code Specifications, CI/CD, and Roadmap](CONTRIBUTING.md).\n","funding_links":[],"categories":["Generators","Go","发电机"],"sub_categories":["Search and Analytic Databases","检索及分析资料库","Utility/Miscellaneous"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswitchupcb%2Fcopygen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswitchupcb%2Fcopygen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswitchupcb%2Fcopygen/lists"}