{"id":15172692,"url":"https://github.com/hujun-open/extyaml","last_synced_at":"2026-02-21T21:03:44.587Z","repository":{"id":171415269,"uuid":"647905892","full_name":"hujun-open/extyaml","owner":"hujun-open","description":"A golang module provides YAML marshaling/unmarshalling for existing type without creating alias type","archived":false,"fork":false,"pushed_at":"2025-03-23T22:37:09.000Z","size":45,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T18:13:06.172Z","etag":null,"topics":["golang","yaml"],"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/hujun-open.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":"2023-05-31T19:28:11.000Z","updated_at":"2025-03-23T22:37:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"fa15b669-8518-4b3e-9861-ee80900033a6","html_url":"https://github.com/hujun-open/extyaml","commit_stats":null,"previous_names":["hujun-open/extyaml"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hujun-open%2Fextyaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hujun-open%2Fextyaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hujun-open%2Fextyaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hujun-open%2Fextyaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hujun-open","download_url":"https://codeload.github.com/hujun-open/extyaml/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248610341,"owners_count":21132919,"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":["golang","yaml"],"created_at":"2024-09-27T10:03:11.665Z","updated_at":"2026-02-21T21:03:44.473Z","avatar_url":"https://github.com/hujun-open.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/hujun-open/extyaml/actions/workflows/main.yaml/badge.svg)](https://github.com/hujun-open/extyaml/actions/workflows/main.yaml)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/hujun-open/extyaml)](https://pkg.go.dev/github.com/hujun-open/extyaml)\n# overview\nextyaml is a golang module that does YAML marshaling/unmarshalling, it builds on top of [gopkg.in/yaml.v3](https://github.com/go-yaml/yaml), to address following use cases:\n\n- YAML support is needed for certain type that not in your control, e.g. a struct in a 3rd party module, but you don't want to create an alias type to add YAML support since that require changing the existing code to use this new type. \n- Marshal result ignore struct fields that has default value, the default value is specified via an input struct\n\n\n## Usage\nProvides a `FromStr` and `ToStr` function for each to-be-support type, and register them using `RegisterExt` function in `init()`. After registration, use `MarshalExt` for marshalling and `UnmarshalExt` for unmarshalling. if the type is already supported by `gopkg.in/yaml.v3`, then the registered functions overrides `gopkg.in/yaml.v3` marshaling/unmarshalling behavior.\n\nNote: If a type implements one of following interface, it will be automatically used without need of registration:\n\n- encoding.TextMarshaler/encoding.TextUnmarshaler\n- gopkg.in/yaml.v3: Marshaler/Unmarshaler\n\n\n\nFollowing is an example using custom layout string for `time.Time`, this overrides `gopkg.in/yaml.v3` marshaling/unmarshalling support for `time.Time`\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hujun-open/extyaml\"\n)\n\ntype ExamplStruct struct {\n\tStrScalar   string\n\tTimePointer *time.Time\n\tTimeScalar  time.Time\n\tTimeArray   [2]time.Time\n\tTimeSlice   []time.Time\n\tTimeMap     map[time.Time]*time.Time\n}\n\nconst myTimeLayout = \"2006-Jan-02,Mon,15:04:05 MST\" //the custom layout\n\nfunc timeFromStr(s string) (any, error) {\n\treturn time.Parse(myTimeLayout, s)\n}\n\nfunc timeToStr(in any) (string, error) {\n\treturn in.(time.Time).Format(myTimeLayout), nil\n}\n\nfunc init() {\n\t//register time.Time, should be called before marshalling/unmarshalling\n\textyaml.RegisterExt[time.Time](timeToStr, timeFromStr)\n}\n\nfunc main() {\n\ts := \u0026ExamplStruct{\n\t\tStrScalar:  \"example\",\n\t\tTimeScalar: time.Date(2022, 12, 1, 1, 2, 3, 0, time.UTC),\n\t\tTimeArray: [2]time.Time{\n\t\t\ttime.Date(2010, 01, 1, 1, 2, 3, 0, time.UTC),\n\t\t\ttime.Date(2010, 12, 1, 1, 2, 3, 0, time.UTC),\n\t\t},\n\t\tTimeSlice: []time.Time{\n\t\t\ttime.Date(2001, 02, 1, 1, 2, 3, 0, time.UTC),\n\t\t\ttime.Date(2001, 03, 1, 1, 2, 3, 0, time.UTC),\n\t\t\ttime.Date(2001, 04, 1, 1, 2, 3, 0, time.UTC),\n\t\t},\n\t}\n\tt := time.Date(1111, 12, 1, 1, 2, 3, 0, time.UTC)\n\ts.TimePointer = \u0026t\n\tt = time.Date(2088, 02, 1, 1, 2, 3, 0, time.UTC)\n\ts.TimeMap = map[time.Time]*time.Time{\n\t\ttime.Date(2099, 02, 1, 1, 2, 3, 0, time.UTC): \u0026t,\n\t}\n\t//marshalling\n\tbuf, err := extyaml.MarshalExt(s)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"marshaling result:\\n\\n%v\\n\", string(buf))\n\t//unmarshalling\n\tnews := new(ExamplStruct)\n\terr = extyaml.UnmarshalExt(buf, news)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"unmarshaling result:\\n%+v\\n\\n\", news)\n\t//partial unmarshalling, where YAML only contains part of struct fields\n\tbuf = []byte(`\ntimescalar: 2022-Dec-01,Thu,01:02:03 UTC\ntimearray:\n    - 2010-Jan-01,Fri,01:02:03 UTC\n    - 2010-Dec-01,Wed,01:02:03 UTC`)\n\tnews = \u0026ExamplStruct{\n\t\tStrScalar:  \"init\",\n\t\tTimeScalar: time.Date(4444, 12, 1, 1, 2, 3, 0, time.UTC),\n\t\tTimeArray: [2]time.Time{\n\t\t\ttime.Date(5555, 01, 1, 1, 2, 3, 0, time.UTC),\n\t\t\ttime.Date(5555, 12, 1, 1, 2, 3, 0, time.UTC),\n\t\t},\n\t}\n\terr = extyaml.UnmarshalExt(buf, news)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"partial unmarshaling result:\\n%+v\\n\", news)\n}\n\n```\nand following the output:\n```\nmarshaling result:\n\nstrscalar: example\ntimepointer: 2088-Feb-01,Sun,01:02:03 UTC\ntimescalar: 2022-Dec-01,Thu,01:02:03 UTC\ntimearray:\n    - 2010-Jan-01,Fri,01:02:03 UTC\n    - 2010-Dec-01,Wed,01:02:03 UTC\ntimeslice:\n    - 2001-Feb-01,Thu,01:02:03 UTC\n    - 2001-Mar-01,Thu,01:02:03 UTC\n    - 2001-Apr-01,Sun,01:02:03 UTC\ntimemap:\n    2099-Feb-01,Sun,01:02:03 UTC: 2088-Feb-01,Sun,01:02:03 UTC\n\nunmarshaling result:\n\u0026{StrScalar:example TimePointer:2088-02-01 01:02:03 +0000 UTC TimeScalar:2022-12-01 01:02:03 +0000 UTC TimeArray:[2010-01-01 01:02:03 +0000 UTC 2010-12-01 01:02:03 +0000 UTC] TimeSlice:[2001-02-01 01:02:03 +0000 UTC 2001-03-01 01:02:03 +0000 UTC 2001-04-01 01:02:03 +0000 UTC] TimeMap:map[2099-02-01 01:02:03 +0000 UTC:2088-02-01 01:02:03 +0000 UTC]}       \n\npartial unmarshaling result:\n\u0026{StrScalar:init TimePointer:0001-01-01 00:00:00 +0000 UTC TimeScalar:2022-12-01 01:02:03 +0000 UTC TimeArray:[2010-01-01 01:02:03 +0000 UTC 2010-12-01 01:02:03 +0000 UTC] TimeSlice:[] TimeMap:map[]}\n```\n\n## Field Tag\nif a struct field declaration contains a `skipyamlmarshal` tag, then it is skipped for marshalling/unmarshalling, even if it is a exported field.\n\n## Post Unmarshal\nif the input type implements `PostUnmarshal` interface, then its method gets called at the end of `UnmarshalExt()`; which could be used for e.g. checking the unmarshalled value. \n\n## Skip default value with MarshalExtDefault\nfunction `MarshalExtDefault` marshal output skips fields that has same value as the specified default value;\nfollowing is an example:\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hujun-open/extyaml\"\n)\n\ntype Foo struct {\n\tName     string\n\tInterval time.Duration\n}\n\nfunc main() {\n\tdefaultVal := Foo{\n\t\tInterval: time.Second * 30,\n\t}\n\tinputVal := Foo{\n\t\tName:     \"example\",\n\t\tInterval: time.Second * 30, //same as defaultVal, skipped in output\n\t}\n\tbuf, err := extyaml.MarshalExtDefault(inputVal, defaultVal)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(string(buf))\n}\n```\nThe output is:\n```\nname: example\n```\n\nLimitation: if there are different element in slice/arrary/map, even same elements are not skipped\n## Included Types\n\nThis module also include support for following types:\n\n- `net.IPNet`: format as supported by `net.ParseCIDR`\n- `net.HardwareAddr`\n    - marshaling: xx:xx:xx:xx:xx:xx\n    - unmarshalling: xx:xx:xx:xx:xx:xx, xx-xx-xx-xx-xx-xx","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhujun-open%2Fextyaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhujun-open%2Fextyaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhujun-open%2Fextyaml/lists"}