{"id":13393946,"url":"https://github.com/dave/jennifer","last_synced_at":"2025-05-13T16:06:27.880Z","repository":{"id":37735276,"uuid":"75564101","full_name":"dave/jennifer","owner":"dave","description":"Jennifer is a code generator for Go","archived":false,"fork":false,"pushed_at":"2024-09-08T22:27:59.000Z","size":449,"stargazers_count":3461,"open_issues_count":17,"forks_count":162,"subscribers_count":35,"default_branch":"master","last_synced_at":"2025-04-08T08:11:12.123Z","etag":null,"topics":["code-generation","code-generator","go","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dave.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":"2016-12-04T20:57:38.000Z","updated_at":"2025-04-08T03:04:43.000Z","dependencies_parsed_at":"2024-12-02T19:30:54.760Z","dependency_job_id":"ce29a662-09a0-43df-9c5d-d139d19fc30c","html_url":"https://github.com/dave/jennifer","commit_stats":{"total_commits":228,"total_committers":14,"mean_commits":"16.285714285714285","dds":0.07017543859649122,"last_synced_commit":"3f94e7e1799d54504d53f8f56a079d2e2353a4cb"},"previous_names":["davelondon/jennifer"],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fjennifer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fjennifer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fjennifer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fjennifer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dave","download_url":"https://codeload.github.com/dave/jennifer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250512761,"owners_count":21443079,"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","go","golang"],"created_at":"2024-07-30T17:01:03.309Z","updated_at":"2025-04-23T20:38:37.690Z","avatar_url":"https://github.com/dave.png","language":"Go","readme":"[![docs](https://pkg.go.dev/badge/github.com/dave/jennifer/jen.svg)](https://pkg.go.dev/github.com/dave/jennifer/jen)\n![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg)\n\n# Jennifer\nJennifer is a code generator for Go.\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n\n    . \"github.com/dave/jennifer/jen\"\n)\n\nfunc main() {\n\tf := NewFile(\"main\")\n\tf.Func().Id(\"main\").Params().Block(\n\t\tQual(\"fmt\", \"Println\").Call(Lit(\"Hello, world\")),\n\t)\n\tfmt.Printf(\"%#v\", f)\n}\n```\nOutput:\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, world\")\n}\n```\n\n### Install\n```\ngo get -u github.com/dave/jennifer/jen\n```\n\n### Need help?\nIf you get stuck, have a question, would like a code review, or just want a\nchat: I'm happy to help! Feel free to open an issue, email me or mention @dave\nin your PR.\n\n### Examples\nJennifer has a comprehensive suite of examples - see [godoc](https://godoc.org/github.com/dave/jennifer/jen#pkg-examples) for an index. Here's some examples of jennifer being used in the real-world:\n\n* [genjen](genjen/render.go) (which generates much of jennifer, using data in [data.go](genjen/data.go))\n* [zerogen](https://github.com/mrsinham/zerogen/blob/master/generator.go)\n* [go-contentful-generator](https://github.com/nicolai86/go-contentful-generator)\n\n### Rendering\nFor testing, a File or Statement can be rendered with the fmt package\nusing the %#v verb.\n\n```go\nc := Id(\"a\").Call(Lit(\"b\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a(\"b\")\n```\n\nThis is not recommended for use in production because any error will cause a\npanic. For production use, [File.Render](#render) or [File.Save](#save) are\npreferred.\n\n# Identifiers\n**Identifiers** [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\n### Id\nId renders an identifier.\n\n```go\nc := If(Id(\"i\").Op(\"==\").Id(\"j\")).Block(\n\tReturn(Id(\"i\")),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// if i == j {\n// \treturn i\n// }\n```\n\n### Dot\nDot renders a period followed by an identifier. Use for fields and selectors.\n\n```go\nc := Qual(\"a.b/c\", \"Foo\").Call().Dot(\"Bar\").Index(Lit(0)).Dot(\"Baz\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// c.Foo().Bar[0].Baz\n```\n\n### Qual\nQual renders a qualified identifier.\n\n```go\nc := Qual(\"encoding/gob\", \"NewEncoder\").Call()\nfmt.Printf(\"%#v\", c)\n// Output:\n// gob.NewEncoder()\n```\n\nImports are automatically added when\nused with a File. If the path matches the local path, the package name is\nomitted. If package names conflict they are automatically renamed.\n\n```go\nf := NewFilePath(\"a.b/c\")\nf.Func().Id(\"init\").Params().Block(\n\tQual(\"a.b/c\", \"Foo\").Call().Comment(\"Local package - name is omitted.\"),\n\tQual(\"d.e/f\", \"Bar\").Call().Comment(\"Import is automatically added.\"),\n\tQual(\"g.h/f\", \"Baz\").Call().Comment(\"Colliding package name is renamed.\"),\n)\nfmt.Printf(\"%#v\", f)\n// Output:\n// package c\n//\n// import (\n// \tf \"d.e/f\"\n// \tf1 \"g.h/f\"\n// )\n//\n// func init() {\n// \tFoo()    // Local package - name is omitted.\n// \tf.Bar()  // Import is automatically added.\n// \tf1.Baz() // Colliding package name is renamed.\n// }\n```\n\nNote that\nit is not possible to reliably determine the package name given an arbitrary\npackage path, so a sensible name is guessed from the path and added as an\nalias. The names of all standard library packages are known so these do not\nneed to be aliased. If more control is needed of the aliases, see\n[File.ImportName](#importname) or [File.ImportAlias](#importalias).\n\n### List\nList renders a comma separated list. Use for multiple return functions.\n\n```go\nc := List(Id(\"a\"), Err()).Op(\":=\").Id(\"b\").Call()\nfmt.Printf(\"%#v\", c)\n// Output:\n// a, err := b()\n```\n\n# Keywords\n[Identifiers](#identifiers) **Keywords** [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\nSimple keywords, predeclared identifiers and built-in functions are self\nexplanatory:\n\n| Construct        | Name |\n| ---------------- | ---- |\n| Keywords         | Break, Chan, Const, Continue, Default, Defer, Else, Fallthrough, Func, Go, Goto, Range, Select, Type, Var |\n| Functions        | Append, Cap, Clear, Close, Complex, Copy, Delete, Imag, Len, Make, Max, Min, New, Panic, Print, Println, Real, Recover |\n| Types            | Bool, Byte, Complex64, Complex128, Error, Float32, Float64, Int, Int8, Int16, Int32, Int64, Rune, String, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr |\n| Constants        | True, False, Iota, Nil |\n| Helpers          | Err |\n\nBuilt-in functions take a list of parameters and render them appropriately:\n\n```go\nc := Id(\"a\").Op(\"=\").Append(Id(\"a\"), Id(\"b\").Op(\"...\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a = append(a, b...)\n```\n\nSpecial cases for [If, For](#if-for), [Interface, Struct](#interface-struct), [Switch, Case](#switch-select), [Return](#return) and [Map](#map) are explained below.\n\n# Operators\n[Identifiers](#identifiers) [Keywords](#keywords) **Operators** [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\nOp renders the provided operator / token.\n\n```go\nc := Id(\"a\").Op(\":=\").Id(\"b\").Call()\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := b()\n```\n\n```go\nc := Id(\"a\").Op(\"=\").Op(\"*\").Id(\"b\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// a = *b\n```\n\n```go\nc := Id(\"a\").Call(Id(\"b\").Op(\"...\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a(b...)\n```\n\n```go\nc := If(Parens(Id(\"a\").Op(\"||\").Id(\"b\")).Op(\"\u0026\u0026\").Id(\"c\")).Block()\nfmt.Printf(\"%#v\", c)\n// Output:\n// if (a || b) \u0026\u0026 c {\n// }\n```\n\n# Braces\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) **Braces** [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\nSeveral methods render curly braces, summarized below:\n\n| Name                           | Prefix       | Separator | Example                              |\n| ------------------------------ | ------------ | --------- | -------------------------------------|\n| [Block](#block)                |              | `\\n`      | `func a() { ... }` or `if a { ... }` |\n| [Interface](#interface-struct) | `interface`  | `\\n`      | `interface { ... }`                  |\n| [Struct](#interface-struct)    | `struct`     | `\\n`      | `struct { ... }`                     |\n| [Values](#values)              |              | `,`       | `[]int{1, 2}` or `A{B: \"c\"}`         |\n\n### Block\nBlock renders a statement list enclosed by curly braces. Use for code blocks.\n\n```go\nc := Func().Id(\"foo\").Params().String().Block(\n\tId(\"a\").Op(\"=\").Id(\"b\"),\n\tId(\"b\").Op(\"++\"),\n\tReturn(Id(\"b\")),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// func foo() string {\n// \ta = b\n// \tb++\n// \treturn b\n// }\n```\n\n```go\nc := If(Id(\"a\").Op(\"\u003e\").Lit(10)).Block(\n\tId(\"a\").Op(\"=\").Id(\"a\").Op(\"/\").Lit(2),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// if a \u003e 10 {\n// \ta = a / 2\n// }\n```\n\nA special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. [See example](#switch-select).\n\n### Interface, Struct\nInterface and Struct render the keyword followed by a statement list enclosed\nby curly braces.\n\n```go\nc := Var().Id(\"a\").Interface()\nfmt.Printf(\"%#v\", c)\n// Output:\n// var a interface{}\n```\n\n```go\nc := Type().Id(\"a\").Interface(\n\tId(\"b\").Params().String(),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// type a interface {\n// \tb() string\n// }\n```\n\n```go\nc := Id(\"c\").Op(\":=\").Make(Chan().Struct())\nfmt.Printf(\"%#v\", c)\n// Output:\n// c := make(chan struct{})\n```\n\n```go\nc := Type().Id(\"foo\").Struct(\n\tList(Id(\"x\"), Id(\"y\")).Int(),\n\tId(\"u\").Float32(),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// type foo struct {\n// \tx, y int\n// \tu    float32\n// }\n```\n\n# Parentheses\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) **Parentheses** [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\nSeveral methods output parenthesis, summarized below:\n\n| Name              | Prefix | Separator | Example                           |\n| ----------------- | ------ | --------- | --------------------------------- |\n| [Call](#call)     |        | `,`       | `fmt.Println(b, c)`               |\n| [Params](#params) |        | `,`       | `func (a *A) Foo(i int) { ... }`  |\n| [Defs](#defs)     |        | `\\n`      | `const ( ... )`                   |\n| [Parens](#parens) |        |           | `[]byte(s)` or `a / (b + c)`      |\n| [Assert](#assert) | `.`    |           | `s, ok := i.(string)`             |\n\n### Call\nCall renders a comma separated list enclosed by parenthesis. Use for function calls.\n\n```go\nc := Qual(\"fmt\", \"Printf\").Call(\n\tLit(\"%#v: %T\\n\"),\n\tId(\"a\"),\n\tId(\"b\"),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// fmt.Printf(\"%#v: %T\\n\", a, b)\n```\n\n### Params\nParams renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers.\n\n```go\nc := Func().Params(\n\tId(\"a\").Id(\"A\"),\n).Id(\"foo\").Params(\n\tId(\"b\"),\n\tId(\"c\").String(),\n).String().Block(\n\tReturn(Id(\"b\").Op(\"+\").Id(\"c\")),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// func (a A) foo(b, c string) string {\n// \treturn b + c\n// }\n```\n\n### Defs\nDefs renders a statement list enclosed in parenthesis. Use for definition lists.\n\n```go\nc := Const().Defs(\n\tId(\"a\").Op(\"=\").Lit(\"a\"),\n\tId(\"b\").Op(\"=\").Lit(\"b\"),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// const (\n// \ta = \"a\"\n// \tb = \"b\"\n// )\n```\n\n### Parens\nParens renders a single item in parenthesis. Use for type conversion or to specify evaluation order.\n\n```go\nc := Id(\"b\").Op(\":=\").Index().Byte().Parens(Id(\"s\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// b := []byte(s)\n```\n\n```go\nc := Id(\"a\").Op(\"/\").Parens(Id(\"b\").Op(\"+\").Id(\"c\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a / (b + c)\n```\n\n### Assert\nAssert renders a period followed by a single item enclosed by parenthesis. Use for type assertions.\n\n```go\nc := List(Id(\"b\"), Id(\"ok\")).Op(\":=\").Id(\"a\").Assert(Bool())\nfmt.Printf(\"%#v\", c)\n// Output:\n// b, ok := a.(bool)\n```\n\n# Control flow\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) **Control flow** [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\n### If, For\nIf and For render the keyword followed by a semicolon separated list.\n\n```go\nc := If(\n\tErr().Op(\":=\").Id(\"a\").Call(),\n\tErr().Op(\"!=\").Nil(),\n).Block(\n\tReturn(Err()),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// if err := a(); err != nil {\n// \treturn err\n// }\n```\n\n```go\nc := For(\n\tId(\"i\").Op(\":=\").Lit(0),\n\tId(\"i\").Op(\"\u003c\").Lit(10),\n\tId(\"i\").Op(\"++\"),\n).Block(\n\tQual(\"fmt\", \"Println\").Call(Id(\"i\")),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// for i := 0; i \u003c 10; i++ {\n// \tfmt.Println(i)\n// }\n```\n\n### Switch, Select\nSwitch, Select, Case and Block are used to build switch or select statements:\n\n```go\nc := Switch(Id(\"value\").Dot(\"Kind\").Call()).Block(\n\tCase(Qual(\"reflect\", \"Float32\"), Qual(\"reflect\", \"Float64\")).Block(\n\t\tReturn(Lit(\"float\")),\n\t),\n\tCase(Qual(\"reflect\", \"Bool\")).Block(\n\t\tReturn(Lit(\"bool\")),\n\t),\n\tCase(Qual(\"reflect\", \"Uintptr\")).Block(\n\t\tFallthrough(),\n\t),\n\tDefault().Block(\n\t\tReturn(Lit(\"none\")),\n\t),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// switch value.Kind() {\n// case reflect.Float32, reflect.Float64:\n// \treturn \"float\"\n// case reflect.Bool:\n// \treturn \"bool\"\n// case reflect.Uintptr:\n// \tfallthrough\n// default:\n// \treturn \"none\"\n// }\n```\n\n### Return\nReturn renders the keyword followed by a comma separated list.\n\n```go\nc := Return(Id(\"a\"), Id(\"b\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// return a, b\n```\n\n# Collections\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) **Collections** [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\n### Map\nMap renders the keyword followed by a single item enclosed by square brackets. Use for map definitions.\n\n```go\nc := Id(\"a\").Op(\":=\").Map(String()).String().Values()\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := map[string]string{}\n```\n\n### Index\nIndex renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions.\n\n```go\nc := Var().Id(\"a\").Index().String()\nfmt.Printf(\"%#v\", c)\n// Output:\n// var a []string\n```\n\n```go\nc := Id(\"a\").Op(\":=\").Id(\"b\").Index(Lit(0), Lit(1))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := b[0:1]\n```\n\n```go\nc := Id(\"a\").Op(\":=\").Id(\"b\").Index(Lit(1), Empty())\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := b[1:]\n```\n\n### Values\nValues renders a comma separated list enclosed by curly braces. Use for slice or composite literals.\n\n```go\nc := Index().String().Values(Lit(\"a\"), Lit(\"b\"))\nfmt.Printf(\"%#v\", c)\n// Output:\n// []string{\"a\", \"b\"}\n```\n\nDict renders as key/value pairs. Use with Values for map or composite\nliterals.\n\n```go\nc := Map(String()).String().Values(Dict{\n\tLit(\"a\"):\tLit(\"b\"),\n\tLit(\"c\"):\tLit(\"d\"),\n})\nfmt.Printf(\"%#v\", c)\n// Output:\n// map[string]string{\n// \t\"a\": \"b\",\n// \t\"c\": \"d\",\n// }\n```\n\n```go\nc := Op(\"\u0026\").Id(\"Person\").Values(Dict{\n\tId(\"Age\"):\tLit(1),\n\tId(\"Name\"):\tLit(\"a\"),\n})\nfmt.Printf(\"%#v\", c)\n// Output:\n// \u0026Person{\n// \tAge:  1,\n// \tName: \"a\",\n// }\n```\n\nDictFunc executes a func(Dict) to generate the value.\n\n```go\nc := Id(\"a\").Op(\":=\").Map(String()).String().Values(DictFunc(func(d Dict) {\n\td[Lit(\"a\")] = Lit(\"b\")\n\td[Lit(\"c\")] = Lit(\"d\")\n}))\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := map[string]string{\n// \t\"a\": \"b\",\n// \t\"c\": \"d\",\n// }\n```\n\nNote: the items are ordered by key when rendered to ensure repeatable code.\n\n# Literals\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) **Literals** [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\n### Lit\nLit renders a literal. Lit supports only built-in types (bool, string, int, complex128, float64,\nfloat32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64).\nPassing any other type will panic.\n\n```go\nc := Id(\"a\").Op(\":=\").Lit(\"a\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := \"a\"\n```\n\n```go\nc := Id(\"a\").Op(\":=\").Lit(1.5)\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := 1.5\n```\n\nLitFunc generates the value to render by executing the provided\nfunction.\n\n```go\nc := Id(\"a\").Op(\":=\").LitFunc(func() interface{} { return 1 + 1 })\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := 2\n```\n\nFor the default constant types (bool, int, float64, string, complex128), Lit\nwill render the untyped constant.\n\n| Code          | Output     |\n| ------------- | ---------- |\n| `Lit(true)`   | `true`     |\n| `Lit(1)`      | `1`        |\n| `Lit(1.0)`    | `1.0`      |\n| `Lit(\"foo\")`  | `\"foo\"`    |\n| `Lit(0 + 1i)` | `(0 + 1i)` |\n\nFor all other built-in types (float32, int8, int16, int32, int64, uint, uint8,\nuint16, uint32, uint64, uintptr, complex64), Lit will also render the type.\n\n| Code                     | Output              |\n| ------------------------ | ------------------- |\n| `Lit(float32(1))`        | `float32(1)`        |\n| `Lit(int16(1))`          | `int16(1)`          |\n| `Lit(uint8(0x1))`        | `uint8(0x1)`        |\n| `Lit(complex64(0 + 1i))` | `complex64(0 + 1i)` |\n\nThe built-in alias types byte and rune need a special case. LitRune and LitByte\nrender rune and byte literals.\n\n| Code                     | Output      |\n| ------------------------ | ----------- |\n| `LitRune('x')`           | `'x'`       |\n| `LitByte(byte(0x1))`     | `byte(0x1)` |\n\n# Comments\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) **Comments** [Generics](#generics) [Helpers](#helpers) [Misc](#misc) [File](#file)\n\n### Comment\nComment adds a comment. If the provided string contains a newline, the\ncomment is formatted in multiline style.\n\n```go\nf := NewFile(\"a\")\nf.Comment(\"Foo returns the string \\\"foo\\\"\")\nf.Func().Id(\"Foo\").Params().String().Block(\n\tReturn(Lit(\"foo\")).Comment(\"return the string foo\"),\n)\nfmt.Printf(\"%#v\", f)\n// Output:\n// package a\n//\n// // Foo returns the string \"foo\"\n// func Foo() string {\n// \treturn \"foo\" // return the string foo\n// }\n```\n\n```go\nc := Comment(\"a\\nb\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// /*\n// a\n// b\n// */\n```\n\nIf the comment string starts\nwith \"//\" or \"/*\", the automatic formatting is disabled and the string is\nrendered directly.\n\n```go\nc := Id(\"foo\").Call(Comment(\"/* inline */\")).Comment(\"//no-space\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// foo( /* inline */ ) //no-space\n```\n\n### Commentf\nCommentf adds a comment, using a format string and a list of parameters.\n\n```go\nname := \"foo\"\nval := \"bar\"\nc := Id(name).Op(\":=\").Lit(val).Commentf(\"%s is the string \\\"%s\\\"\", name, val)\nfmt.Printf(\"%#v\", c)\n// Output:\n// foo := \"bar\" // foo is the string \"bar\"\n```\n\n# Generics\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) **Generics** [Helpers](#helpers) [Misc](#misc) [File](#file)\n\nIt is hoped that with the introduction of generics with Go 1.18, the need to generate code\nwill be reduced. However, for the sake of completeness, we now support generics including\nthe `any` and `comparable` predeclared identifiers, and the `Types` and `Union` lists. To\nemit the approximation (`~`) token, use `Op(\"~\")`.\n\n### Types\n\nTypes renders a comma separated list enclosed by square brackets. Use for type parameters and constraints.\n\n### Union\n\nUnion renders a pipe separated list. Use for union type constraints.\n\n### Examples\n\n```go\nc := Func().Id(\"Keys\").Types(\n\tId(\"K\").Comparable(),\n\tId(\"V\").Any(),\n).Params(\n\tId(\"m\").Map(Id(\"K\")).Id(\"V\"),\n).Index().Id(\"K\").Block()\nfmt.Printf(\"%#v\", c)\n// Output:\n// func Keys[K comparable, V any](m map[K]V) []K {}\n```\n```go\nc := Return(Id(\"Keys\").Types(Int(), String()).Call(Id(\"m\")))\nfmt.Printf(\"%#v\", c)\n// Output:\n// return Keys[int, string](m)\n```\n```go\nc := Type().Id(\"PredeclaredSignedInteger\").Interface(\n\tUnion(Int(), Int8(), Int16(), Int32(), Int64()),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// type PredeclaredSignedInteger interface {\n//\tint | int8 | int16 | int32 | int64\n// }\n```\n```go\nc := Type().Id(\"AnyString\").Interface(\n\tOp(\"~\").String(),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// type AnyString interface {\n//\t~string\n// }\n```\n\n# Helpers\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) **Helpers** [Misc](#misc) [File](#file)\n\n### Func methods\nAll constructs that accept a variadic list of items are paired with GroupFunc\nfunctions that accept a func(*Group). Use for embedding logic.\n\n```go\nc := Id(\"numbers\").Op(\":=\").Index().Int().ValuesFunc(func(g *Group) {\n\tfor i := 0; i \u003c= 5; i++ {\n\t\tg.Lit(i)\n\t}\n})\nfmt.Printf(\"%#v\", c)\n// Output:\n// numbers := []int{0, 1, 2, 3, 4, 5}\n```\n\n```go\nincrement := true\nname := \"a\"\nc := Func().Id(\"a\").Params().BlockFunc(func(g *Group) {\n\tg.Id(name).Op(\"=\").Lit(1)\n\tif increment {\n\t\tg.Id(name).Op(\"++\")\n\t} else {\n\t\tg.Id(name).Op(\"--\")\n\t}\n})\nfmt.Printf(\"%#v\", c)\n// Output:\n// func a() {\n// \ta = 1\n// \ta++\n// }\n```\n\n### Add\nAdd appends the provided items to the statement.\n\n```go\nptr := Op(\"*\")\nc := Id(\"a\").Op(\"=\").Add(ptr).Id(\"b\")\nfmt.Printf(\"%#v\", c)\n// Output:\n// a = *b\n```\n\n```go\na := Id(\"a\")\ni := Int()\nc := Var().Add(a, i)\nfmt.Printf(\"%#v\", c)\n// Output:\n// var a int\n```\n\n### Do\nDo calls the provided function with the statement as a parameter. Use for\nembedding logic.\n\n```go\nf := func(name string, isMap bool) *Statement {\n\treturn Id(name).Op(\":=\").Do(func(s *Statement) {\n\t\tif isMap {\n\t\t\ts.Map(String()).String()\n\t\t} else {\n\t\t\ts.Index().String()\n\t\t}\n\t}).Values()\n}\nfmt.Printf(\"%#v\\n%#v\", f(\"a\", true), f(\"b\", false))\n// Output:\n// a := map[string]string{}\n// b := []string{}\n```\n\n# Misc\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) **Misc** [File](#file)\n\n### Tag\nTag renders a struct tag\n\n```go\nc := Type().Id(\"foo\").Struct(\n\tId(\"A\").String().Tag(map[string]string{\"json\": \"a\"}),\n\tId(\"B\").Int().Tag(map[string]string{\"json\": \"b\", \"bar\": \"baz\"}),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// type foo struct {\n// \tA string `json:\"a\"`\n// \tB int    `bar:\"baz\" json:\"b\"`\n// }\n```\n\nNote: the items are ordered by key when rendered to ensure repeatable code.\n\n### Null\nNull adds a null item. Null items render nothing and are not followed by a\nseparator in lists.\n\nIn lists, nil will produce the same effect.\n\n```go\nc := Func().Id(\"foo\").Params(\n\tnil,\n\tId(\"s\").String(),\n\tNull(),\n\tId(\"i\").Int(),\n).Block()\nfmt.Printf(\"%#v\", c)\n// Output:\n// func foo(s string, i int) {}\n```\n\n### Empty\nEmpty adds an empty item. Empty items render nothing but are followed by a\nseparator in lists.\n\n```go\nc := Id(\"a\").Op(\":=\").Id(\"b\").Index(Lit(1), Empty())\nfmt.Printf(\"%#v\", c)\n// Output:\n// a := b[1:]\n```\n\n### Line\nLine inserts a blank line.\n\n### Clone\nBe careful when passing *Statement. Consider the following...\n\n```go\na := Id(\"a\")\nc := Block(\n\ta.Call(),\n\ta.Call(),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// {\n// \ta()()\n// \ta()()\n// }\n```\n\nId(\"a\") returns a *Statement, which the Call() method appends to twice. To\navoid this, use Clone. Clone makes a copy of the Statement, so further tokens can be appended\nwithout affecting the original.\n\n```go\na := Id(\"a\")\nc := Block(\n\ta.Clone().Call(),\n\ta.Clone().Call(),\n)\nfmt.Printf(\"%#v\", c)\n// Output:\n// {\n// \ta()\n// \ta()\n// }\n```\n\n### Cgo\nThe cgo \"C\" pseudo-package is a special case, and always renders without a package alias. The\nimport can be added with `Qual`, `Anon` or by supplying a preamble. The preamble is added with\n`File.CgoPreamble` which has the same semantics as [Comment](#comments). If a preamble is provided,\nthe import is separated, and preceded by the preamble.\n\n```go\nf := NewFile(\"a\")\nf.CgoPreamble(`#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\nvoid myprint(char* s) {\nprintf(\"%s\\n\", s);\n}\n`)\nf.Func().Id(\"init\").Params().Block(\n\tId(\"cs\").Op(\":=\").Qual(\"C\", \"CString\").Call(Lit(\"Hello from stdio\\n\")),\n\tQual(\"C\", \"myprint\").Call(Id(\"cs\")),\n\tQual(\"C\", \"free\").Call(Qual(\"unsafe\", \"Pointer\").Parens(Id(\"cs\"))),\n)\nfmt.Printf(\"%#v\", f)\n// Output:\n// package a\n//\n// import \"unsafe\"\n//\n// /*\n// #include \u003cstdio.h\u003e\n// #include \u003cstdlib.h\u003e\n//\n// void myprint(char* s) {\n// \tprintf(\"%s\\n\", s);\n// }\n// */\n// import \"C\"\n//\n// func init() {\n// \tcs := C.CString(\"Hello from stdio\\n\")\n// \tC.myprint(cs)\n// \tC.free(unsafe.Pointer(cs))\n// }\n```\n\n# File\n[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Generics](#generics) [Helpers](#helpers) [Misc](#misc) **File**\n\nFile represents a single source file. Package imports are managed\nautomatically by File.\n\n### NewFile\nNewFile Creates a new file, with the specified package name.\n\n### NewFilePath\nNewFilePath creates a new file while specifying the package path - the\npackage name is inferred from the path.\n\n### NewFilePathName\nNewFilePathName creates a new file with the specified package path and name.\n\n```go\nf := NewFilePathName(\"a.b/c\", \"main\")\nf.Func().Id(\"main\").Params().Block(\n\tQual(\"a.b/c\", \"Foo\").Call(),\n)\nfmt.Printf(\"%#v\", f)\n// Output:\n// package main\n//\n// func main() {\n// \tFoo()\n// }\n```\n\n### Save\nSave renders the file and saves to the filename provided.\n\n### Render\nRender renders the file to the provided writer.\n\n```go\nf := NewFile(\"a\")\nf.Func().Id(\"main\").Params().Block()\nbuf := \u0026bytes.Buffer{}\nerr := f.Render(buf)\nif err != nil {\n\tfmt.Println(err.Error())\n} else {\n\tfmt.Println(buf.String())\n}\n// Output:\n// package a\n//\n// func main() {}\n```\n\n### Anon\nAnon adds an anonymous import.\n\n```go\nf := NewFile(\"c\")\nf.Anon(\"a\")\nf.Func().Id(\"init\").Params().Block()\nfmt.Printf(\"%#v\", f)\n// Output:\n// package c\n//\n// import _ \"a\"\n//\n// func init() {}\n```\n\n### ImportName\nImportName provides the package name for a path. If specified, the alias will be omitted from the\nimport block. This is optional. If not specified, a sensible package name is used based on the path\nand this is added as an alias in the import block.\n\n```go\nf := NewFile(\"main\")\n\n// package a should use name \"a\"\nf.ImportName(\"github.com/foo/a\", \"a\")\n\n// package b is not used in the code so will not be included\nf.ImportName(\"github.com/foo/b\", \"b\")\n\nf.Func().Id(\"main\").Params().Block(\n\tQual(\"github.com/foo/a\", \"A\").Call(),\n)\nfmt.Printf(\"%#v\", f)\n\n// Output:\n// package main\n//\n// import \"github.com/foo/a\"\n//\n// func main() {\n// \ta.A()\n// }\n```\n\n### ImportNames\nImportNames allows multiple names to be imported as a map. Use the [gennames](gennames) command to\nautomatically generate a go file containing a map of a selection of package names.\n\n### ImportAlias\nImportAlias provides the alias for a package path that should be used in the import block. A\nperiod can be used to force a dot-import.\n\n```go\nf := NewFile(\"main\")\n\n// package a should be aliased to \"b\"\nf.ImportAlias(\"github.com/foo/a\", \"b\")\n\n// package c is not used in the code so will not be included\nf.ImportAlias(\"github.com/foo/c\", \"c\")\n\nf.Func().Id(\"main\").Params().Block(\n\tQual(\"github.com/foo/a\", \"A\").Call(),\n)\nfmt.Printf(\"%#v\", f)\n\n// Output:\n// package main\n//\n// import b \"github.com/foo/a\"\n//\n// func main() {\n// \tb.A()\n// }\n```\n\n### Comments\nPackageComment adds a comment to the top of the file, above the package\nkeyword.\n\nHeaderComment adds a comment to the top of the file, above any package\ncomments. A blank line is rendered below the header comments, ensuring\nheader comments are not included in the package doc.\n\nCanonicalPath adds a canonical import path annotation to the package clause.\n\n```go\nf := NewFile(\"c\")\nf.CanonicalPath = \"d.e/f\"\nf.HeaderComment(\"Code generated by...\")\nf.PackageComment(\"Package c implements...\")\nf.Func().Id(\"init\").Params().Block()\nfmt.Printf(\"%#v\", f)\n// Output:\n// // Code generated by...\n//\n// // Package c implements...\n// package c // import \"d.e/f\"\n//\n// func init() {}\n```\n\nCgoPreamble adds a cgo preamble comment that is rendered directly before the \"C\" pseudo-package\nimport.\n\n### PackagePrefix\nIf you're worried about generated package aliases conflicting with local variable names, you\ncan set a prefix here. Package foo becomes {prefix}_foo.\n\n```go\nf := NewFile(\"a\")\nf.PackagePrefix = \"pkg\"\nf.Func().Id(\"main\").Params().Block(\n\tQual(\"b.c/d\", \"E\").Call(),\n)\nfmt.Printf(\"%#v\", f)\n// Output:\n// package a\n//\n// import pkg_d \"b.c/d\"\n//\n// func main() {\n// \tpkg_d.E()\n// }\n```\n\n### NoFormat\nNoFormat can be set to true to disable formatting of the generated source. This may be useful\nwhen performance is critical, and readable code is not required.","funding_links":[],"categories":["代码生成与泛型","Misc","开源类库","Go","Generation and Generics","Backend","Code Generator","Code generators","\u003cspan id=\"代和泛型-generation-and-generics\"\u003e代和泛型 Generation and Generics\u003c/span\u003e","Open source library","Generators","Repositories","HarmonyOS","golang","发电机","代碼生成與泛型","Relational Databases"],"sub_categories":["SQL 查询语句构建库","代码生成","Advanced Console UIs","Golang","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e","Code Generation","Search and Analytic Databases","Windows Manager","检索及分析资料库","高級控制台界面","Utility/Miscellaneous","高级控制台界面"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fjennifer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdave%2Fjennifer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fjennifer/lists"}