{"id":23946167,"url":"https://github.com/ermos/annotation","last_synced_at":"2026-06-14T12:33:13.667Z","repository":{"id":57563104,"uuid":"315371502","full_name":"ermos/annotation","owner":"ermos","description":"🎉 Annotation implementation for Go","archived":false,"fork":false,"pushed_at":"2021-03-09T13:26:14.000Z","size":16,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-24T07:16:11.250Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ermos.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}},"created_at":"2020-11-23T16:16:39.000Z","updated_at":"2021-03-09T13:26:17.000Z","dependencies_parsed_at":"2022-09-16T10:40:52.275Z","dependency_job_id":null,"html_url":"https://github.com/ermos/annotation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ermos/annotation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ermos%2Fannotation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ermos%2Fannotation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ermos%2Fannotation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ermos%2Fannotation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ermos","download_url":"https://codeload.github.com/ermos/annotation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ermos%2Fannotation/sbom","scorecard":{"id":381534,"data":{"date":"2025-08-11","repo":{"name":"github.com/ermos/annotation","commit":"a4e71ea8028f9679834bf58c91e10f4ddef43870"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/16 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-18T15:33:39.935Z","repository_id":57563104,"created_at":"2025-08-18T15:33:39.936Z","updated_at":"2025-08-18T15:33:39.936Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34322073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-01-06T08:28:47.620Z","updated_at":"2026-06-14T12:33:13.651Z","avatar_url":"https://github.com/ermos.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Annotation 🎉\n\u003e Annotation implementation for Go\n\nAnnotation's library allows you to use annotations inside you're golang application, it is fully customizable, you can use you're own parser and build you're own annotation rule. You can use or find some examples in `parser` directory.\n\n## Installation\n\n```bash\ngo get github.com/ermos/annotation\n```\n\n## What does it look like? 🧐\n\n```go\n/*\n\t@Route(\"POST\", \"/auth/signin\")\n\t@Desc(\"sign in to the application\")\n\t@Response([200, 500])\n\t@Payload(\"username\", string)\n\t@Payload(\"password\", string)\n\t@?Payload(\"2fa\", string)\n  \n  Allows users to get JSON Web Token :)\n*/\nfunc (Handler) SignIn() {\n\t// Logic here\n}\n```\n\nAnnotations can be recognized from others comments thanks to this `@` before each resource. In this example, we have six resource and one (useless?) comment. Each resource is recognize from their keys, for example, `@Route` is a key that contains `(\"POST\", \"/auth/signin\")`. Data's key logic is decided by you're parser, always for this example, if you looking into `parser/api.go`, in the `(API)._route` method, you can find the regex that decides how you need to write the data.\n\n## Usage\n\nThe most important thing to know before starting to use it, **annotations are generated from .go source file**. Like you can see, this can't be used in production, because you can't access to your source file, so who use it correctly? Firstly, we need to implement a build mode, after that, we can simply store annotations in a `json` file when we build the binary, with `go generate` for example, and use it with importing `json` file into our application on startup.\n\nThe inconvenient about this solution, you need to pass the `json` file on your production server too. You can solve it with embed you're `json` file into you're binary when you compile it. You have some awesome library to do that like [packr](https://github.com/gobuffalo/packr) or [pkger](https://github.com/markbates/pkger).\n\n**Update** : Go 1.16 include a new embed system. Now, you can directly import your json file into your binary with\n``go:embed`` directive, see more information [here](https://golang.org/pkg/embed/).\n\n## Simple Example\n\nWork in progress..\n\n## Custom Parser\n\nWe want to build a simple cron parser for a dynamic cron system.\nIn this example, we use [robfig/cron](https://github.com/robfig/cron) package.\n\nFirst, we will create our parser package and include in a go file.\n\nThe principle is simple, we have an array of structure and we will populate it with data get into\nannotation.\n\nSo, your package need a ``structure`` to receive data and a ``parser's function`` for populate it.\n\nYou can design your structure like what you want, this is the goal of this package.\n\nYour function need to contains two parameters.\nIn first parameter, she needs a ``reflect.Value``, this is your structure array,\nand a ``annotation.Result`` that contains all found annotations.\n\nThe result of your function need to be an error, if you return an error,\nyour program can catch it from ``annotation.Fetch`'s method.\n\nSee the result :\n```go\ntype Cron struct {\n    Quartz string\n    TZ     string\n    Method string\n}\n\nfunc ToCron(rv reflect.Value, ar annotation.Result) (err error) {\n\t...\n\treturn nil\n}\n```\n\nAfter that, we need to use ``annotation.Result`` for getting data and parse it,\nin firstly we can group each annotation for each method like that :\n\n```go\nfunc ToCron(rv reflect.Value, ar annotation.Result) (err error) {\n    mapper := make(map[string]annotation.Result)\n    \n    for _, item := range ar {\n        if mapper[item.Method] == nil {\n            mapper[item.Method] = annotation.Result{}\n        }\n        mapper[item.Method] = append(mapper[item.Method], item)\n    }\n    \n    return nil\n}\n```\n\nWe rebuild ``annotation.Result``'s parameter to a map with string key where the key is the\nmethod name.\n\nNext, we can loop into your new map for insert each annotation information to his method\nand finally append structure into the array of structure :\n```go\nfunc ToCron(rv reflect.Value, ar annotation.Result) (err error) {\n    ...\n    \n    for _, list := range mapper {\n        var c Cron\n        for _, item := range list {\n            if c.Method == \"\" {\n                c.Method = item.Method\n            }\n            err = c.insert(item.Key, item.Data)\n            if err != nil {\n                return\n            }\n        }\n        rv.Set(reflect.Append(rv, reflect.ValueOf(a)))\n    }\n    \n    return nil\n}\n```\n\nYou have probably seen the ``c.insert``'s function, this is simply a switch case based on\nthe annotation key that allows to use the right parsing process, see :\n\n```go\nfunc (c *Cron) insert(key string, data string) error {\n\tswitch strings.ToLower(key) {\n\t    case \"cron\":\n\t    \treturn a._cron(data)\n\t    case \"tz\":\n\t    \treturn a._tz(data)\n\t}\n\treturn nil\n}\n\nfunc (c *Cron) _cron(data string) error {\n\tc.Quartz = data\n    return nil\n}\n```\n\nAll it's good, we can now use it into `annotation`'s package :\n\n```go\nfunc main() {\n\t...\n\tvar c []cronParser.Cron\n\t\n\terr := annotation.Fetch(\"./internal/cron\", \u0026c, cronParser.ToCron)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t\n\terr = annotation.Save(c, \"cron.json\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t...\n}\n```\n\nExample of a controller :\n\n```go\n/*\n    @cron(\"3 30 * * * *\")\n    @tz(\"Europe/Paris\")\n */\nfunc (Handler) Method(...) ... {\n\t...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fermos%2Fannotation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fermos%2Fannotation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fermos%2Fannotation/lists"}