{"id":13600319,"url":"https://github.com/bytedance/go-tagexpr","last_synced_at":"2025-05-14T19:08:38.473Z","repository":{"id":37405466,"uuid":"166369622","full_name":"bytedance/go-tagexpr","owner":"bytedance","description":"An interesting go struct tag expression syntax for field validation, etc.","archived":false,"fork":false,"pushed_at":"2024-03-13T21:29:28.000Z","size":479,"stargazers_count":1697,"open_issues_count":27,"forks_count":141,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-04-13T13:26:47.149Z","etag":null,"topics":["binding","dsl","expression","go","struct-tag","validator"],"latest_commit_sha":null,"homepage":null,"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/bytedance.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":"2019-01-18T08:18:39.000Z","updated_at":"2025-04-08T04:04:09.000Z","dependencies_parsed_at":"2022-07-08T17:47:53.651Z","dependency_job_id":"434b9b0d-db01-416d-914f-88fb3ae781f9","html_url":"https://github.com/bytedance/go-tagexpr","commit_stats":{"total_commits":376,"total_committers":18,"mean_commits":20.88888888888889,"dds":0.1728723404255319,"last_synced_commit":"67da08d2c3c3210d423da48522c533264024bc48"},"previous_names":[],"tags_count":72,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgo-tagexpr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgo-tagexpr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgo-tagexpr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgo-tagexpr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytedance","download_url":"https://codeload.github.com/bytedance/go-tagexpr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254209859,"owners_count":22032897,"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":["binding","dsl","expression","go","struct-tag","validator"],"created_at":"2024-08-01T18:00:36.001Z","updated_at":"2025-05-14T19:08:37.211Z","avatar_url":"https://github.com/bytedance.png","language":"Go","funding_links":[],"categories":["Misc","开源类库","Repositories","Go","Open source library","others"],"sub_categories":["表单","Form"],"readme":"# go-tagexpr [![report card](https://goreportcard.com/badge/github.com/bytedance/go-tagexpr?style=flat-square)](http://goreportcard.com/report/bytedance/go-tagexpr) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/bytedance/go-tagexpr)\n\nAn interesting go struct tag expression syntax for field validation, etc.\n\n## Usage\n\n- **[Validator](https://github.com/bytedance/go-tagexpr/tree/master/validator)**: A powerful validator that supports struct tag expression\n\n- **[Binding](https://github.com/bytedance/go-tagexpr/tree/master/binding)**: A powerful HTTP request parameters binder that supports struct tag expression\n\n## Feature\n\n- Support for a variety of common operator\n- Support for accessing arrays, slices, members of the dictionary\n- Support access to any field in the current structure\n- Support access to nested fields, non-exported fields, etc.\n- Support variable\n- Support registers function expression\n- Built-in len, sprintf, regexp functions\n- Support single mode and multiple mode to define expression\n- Parameter check subpackage\n- Use offset pointers to directly take values, better performance\n- Required go version ≥1.9\n\n## Example\n\n```go\npackage tagexpr_test\n\nimport (\n\t\"fmt\"\n\n\ttagexpr \"github.com/bytedance/go-tagexpr/v2\"\n)\n\nfunc Example() {\n\ttype T struct {\n\t\tA  int             `tagexpr:\"$\u003c0||$\u003e=100\"`\n\t\tB  string          `tagexpr:\"len($)\u003e1 \u0026\u0026 regexp('^\\\\w*$')\"`\n\t\tC  bool            `tagexpr:\"expr1:(f.g)$\u003e0 \u0026\u0026 $; expr2:'C must be true when T.f.g\u003e0'\"`\n\t\td  []string        `tagexpr:\"@:len($)\u003e0 \u0026\u0026 $[0]=='D'; msg:sprintf('invalid d: %v',$)\"`\n\t\te  map[string]int  `tagexpr:\"len($)==$['len']\"`\n\t\te2 map[string]*int `tagexpr:\"len($)==$['len']\"`\n\t\tf  struct {\n\t\t\tg int `tagexpr:\"$\"`\n\t\t}\n\t\th  int \t\t\t\t`tagexpr:\"$\u003eminVal\"`\n\t}\n\n\tvm := tagexpr.New(\"tagexpr\")\n\tt := \u0026T{\n\t\tA:  107,\n\t\tB:  \"abc\",\n\t\tC:  true,\n\t\td:  []string{\"x\", \"y\"},\n\t\te:  map[string]int{\"len\": 1},\n\t\te2: map[string]*int{\"len\": new(int)},\n\t\tf: struct {\n\t\t\tg int `tagexpr:\"$\"`\n\t\t}{1},\n\t\th: 10,\n\t}\n\n\ttagExpr, err := vm.Run(t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(tagExpr.Eval(\"A\"))\n\tfmt.Println(tagExpr.Eval(\"B\"))\n\tfmt.Println(tagExpr.Eval(\"C@expr1\"))\n\tfmt.Println(tagExpr.Eval(\"C@expr2\"))\n\tif !tagExpr.Eval(\"d\").(bool) {\n\t\tfmt.Println(tagExpr.Eval(\"d@msg\"))\n\t}\n\tfmt.Println(tagExpr.Eval(\"e\"))\n\tfmt.Println(tagExpr.Eval(\"e2\"))\n\tfmt.Println(tagExpr.Eval(\"f.g\"))\n\tfmt.Println(tagExpr.EvalWithEnv(\"h\", map[string]interface{}{\"minVal\": 9}))\n\tfmt.Println(tagExpr.EvalWithEnv(\"h\", map[string]interface{}{\"minVal\": 11}))\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// C must be true when T.f.g\u003e0\n\t// invalid d: [x y]\n\t// true\n\t// false\n\t// 1\n\t// true\n\t// false\n}\n```\n\n## Syntax\n\nStruct tag syntax spec:\n\n```\ntype T struct {\n\t// Single model\n    Field1 T1 `tagName:\"expression\"`\n\t// Multiple model\n    Field2 T2 `tagName:\"exprName:expression; [exprName2:expression2;]...\"`\n\t// Omit it\n    Field3 T3 `tagName:\"-\"`\n    // Omit it when it is nil\n    Field4 T4 `tagName:\"?\"`\n    ...\n}\n```\n\nNOTE: **The `exprName` under the same struct field cannot be the same！**\n\n|Operator or Operand|Explain|\n|-----|---------|\n|`true` `false`|boolean|\n|`0` `0.0`|float64 \"0\"|\n|`''`|String|\n|`\\\\'`| Escape `'` delims in string|\n|`\\\"`| Escape `\"` delims in string|\n|`nil`|nil, undefined|\n|`!`|not|\n|`+`|Digital addition or string splicing|\n|`-`|Digital subtraction or negative|\n|`*`|Digital multiplication|\n|`/`|Digital division|\n|`%`|division remainder, as: `float64(int64(a)%int64(b))`|\n|`==`|`eq`|\n|`!=`|`ne`|\n|`\u003e`|`gt`|\n|`\u003e=`|`ge`|\n|`\u003c`|`lt`|\n|`\u003c=`|`le`|\n|`\u0026\u0026`|Logic `and`|\n|`\\|\\|`|Logic `or`|\n|`()`|Expression group|\n|`(X)$`|Struct field value named X|\n|`(X.Y)$`|Struct field value named X.Y|\n|`$`|Shorthand for `(X)$`, omit `(X)` to indicate current struct field value|\n|`(X)$['A']`|Map value with key A or struct A sub-field in the struct field X|\n|`(X)$[0]`|The 0th element or sub-field of the struct field X(type: map, slice, array, struct)|\n|`len((X)$)`|Built-in function `len`, the length of struct field X|\n|`mblen((X)$)`|the length of string field X (character number)|\n|`regexp('^\\\\w*$', (X)$)`|Regular match the struct field X, return boolean|\n|`regexp('^\\\\w*$')`|Regular match the current struct field, return boolean|\n|`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|\n|`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary \u003cbr\u003e - `#k` is the element key var \u003cbr\u003e - `#v` is the element value var \u003cbr\u003e - `##` is the number of elements \u003cbr\u003e - e.g. [example](spec_range_test.go)|\n|`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|\n\n\u003c!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)|\n|`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| --\u003e\n\n\u003c!-- |`\u0026`|Integer bitwise `and`|\n|`\\|`|Integer bitwise `or`|\n|`^`|Integer bitwise `not` or `xor`|\n|`\u0026^`|Integer bitwise `clean`|\n|`\u003c\u003c`|Integer bitwise `shift left`|\n|`\u003e\u003e`|Integer bitwise `shift right`| --\u003e\n\nOperator priority(high -\u003e low):\n\n* `()` `!` `bool` `float64` `string` `nil`\n* `*` `/` `%`\n* `+` `-`\n* `\u003c` `\u003c=` `\u003e` `\u003e=`\n* `==` `!=`\n* `\u0026\u0026`\n* `||`\n\n## Field Selector\n\n```\nfield_lv1.field_lv2...field_lvn\n```\n\n## Expression Selector\n\n- If expression is **single model** or exprName is `@`:\n\n```\nfield_lv1.field_lv2...field_lvn\n```\n\n- If expression is **multiple model** and exprName is not `@`:\n\n```\nfield_lv1.field_lv2...field_lvn@exprName\n```\n\n## Benchmark\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/bytedance/go-tagexpr\nBenchmarkTagExpr-4   \t10000000\t       148 ns/op\t      32 B/op\t       3 allocs/op\nBenchmarkReflect-4   \t10000000\t       182 ns/op\t      16 B/op\t       2 allocs/op\nPASS\n```\n\n[Go to test code](https://github.com/bytedance/go-tagexpr/blob/master/tagexpr_test.go#L9-L56)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fgo-tagexpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytedance%2Fgo-tagexpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fgo-tagexpr/lists"}