{"id":27969198,"url":"https://github.com/future-architect/tagscanner","last_synced_at":"2025-08-31T17:48:38.921Z","repository":{"id":59043369,"uuid":"526604257","full_name":"future-architect/tagscanner","owner":"future-architect","description":"Go's tag field helper. This library supports both static code generation and runtime reflection.","archived":false,"fork":false,"pushed_at":"2023-01-26T07:37:08.000Z","size":70,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-07-26T11:47:43.151Z","etag":null,"topics":[],"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/future-architect.png","metadata":{"files":{"readme":"README.ja.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":"2022-08-19T12:46:14.000Z","updated_at":"2022-08-19T12:56:18.000Z","dependencies_parsed_at":"2023-02-14T15:00:28.322Z","dependency_job_id":null,"html_url":"https://github.com/future-architect/tagscanner","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/future-architect/tagscanner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/future-architect%2Ftagscanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/future-architect%2Ftagscanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/future-architect%2Ftagscanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/future-architect%2Ftagscanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/future-architect","download_url":"https://codeload.github.com/future-architect/tagscanner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/future-architect%2Ftagscanner/sbom","scorecard":{"id":414677,"data":{"date":"2025-08-11","repo":{"name":"github.com/future-architect/tagscanner","commit":"b9de08977e4f77da727807bbd6e77819a5b046f9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"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":"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":"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":"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":"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":"Code-Review","score":0,"reason":"Found 0/22 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":"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":"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":"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: Apache License 2.0: 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"}},{"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3770 / GHSA-vrw8-fxc6-2r93","Warn: Project is vulnerable to: GO-2022-0603 / GHSA-hp87-p4gw-j4gq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T23:31:51.300Z","repository_id":59043369,"created_at":"2025-08-18T23:31:51.300Z","updated_at":"2025-08-18T23:31:51.300Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273018125,"owners_count":25031596,"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","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"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-05-07T21:09:00.388Z","updated_at":"2025-08-31T17:48:38.864Z","avatar_url":"https://github.com/future-architect.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tagscanner\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/future-architect/tagscanner.svg)](https://pkg.go.dev/github.com/future-architect/tagscanner)\n\nこのパッケージは構造体のタグを使って外部データとのやりとりをするライブラリを作成するためのヘルパーライブラリです。\n\nリフレクションやGoのコード解析、型のマッピングの処理をカプセル化します。\n\n主に3つの機能があります。\n\n* 構造体のデータを外部に書き出す(``runtimescan.Encode()``)\n* 外部のデータを構造体の書き込む(``runtimescan.Decode()``)\n* 構造体を元にコード生成を行う(``staticscan.Scan()``)\n\n``runtimescan``パッケージは、実行時に動的に構造体をパースして処理します。\n``staticscan``パッケージは、静的解析・コードジェネレータ用です。\n\n## 実行時の処理\n\n用語としては、構造体に書き込む方をデコード、構造体からの読み出しをエンコードと呼んでいます（``encoding/json``と同じ）。\n\nデコードでは``Decoder``インタフェースを、エンコードでは``Encoder``インタフェースを実装します。\nインタフェースのインスタンスをそれぞれ、``runtimescan.Decode()``、``runtimescan.Encode()``関数に渡します。\n\nエンコード、デコードの両方で、まずは構造体のフィールドを解析し、上記のインタフェースの``ParseTag()``を呼び出します。\nこの中でタグの値を分析したりします。このメソッドの返り値は次の処理で利用されます。\n\nデコード処理では``ExtractValue()``が呼ばれます。呼ばれるときには``ParseTag()``の返したタグの分析情報のインスタンスが引数として渡されます。\nこのメソッドが返した値が、構造体にセットされます。\n\nエンコード処理では``VisitField()``が呼ばれます。こちらも呼ばれるときには``ParseTag()``の返したタグの分析情報のインスタンスが引数として渡されます。\nそれ以外にフィールドの値も引数として渡されます。\n\n### 基本の使い方\n\n#### 構造体のデータを外部に書き出す(``runtimescan.Encode()``)\n\nまずは``Encoder``インタフェースを満たす構造体を作ります。出力先を構造体のフィールドに設定しておきます。\n\n``encoding/json``の基本のように、タグにはフィールド名のみを入れたい場合は``runtimescan.BasicParseTag()``というヘルパー関数もあります。\n\n``VisitField()``に渡されてくる値を出力先に設定していけば実装完了です。\n\n```go\ntype encoder struct {\n\tdest map[string]any\n}\n\nfunc (m encoder) ParseTag(name, tagStr, pathStr string, elemType reflect.Type) (tag any, err error) {\n\treturn runtimescan.BasicParseTag(name, tagStr, pathStr, elemType)\n}\n\nfunc (m *encoder) VisitField(tag, value any) (err error) {\n\tt := tag.(*runtimescan.BasicTag)\n\tm.dest[t.Tag] = value\n\treturn nil\n}\n\nfunc (m encoder) EnterChild(tag any) (err error) {\n\treturn nil\n}\n\nfunc (m encoder) LeaveChild(tag any) (err error) {\n\treturn nil\n}\n```\n\n最後に、ユーザー向けのAPIの関数を作ります。\n\n```go\nfunc Encode(dest map[string]any, src any) error {\n\tenc := \u0026encoder{\n\t\tdest: dest,\n\t}\n\treturn runtimescan.Encode(src, \"map\", enc)\n}\n```\n\n#### 外部のデータを構造体の書き込む(``runtimescan.Decode()``)\n\nまずは``Decoder``インタフェースを満たす構造体を作ります。入力元を構造体のフィールドに設定しておきます。\n\nこの``ExtractValue()``の返り値が最終的に構造体に書き込まれます。構造体に設定した入力用データから、タグの情報を元に取り出してきて返り値として返すことで、\nあとはライブラリがフィールドに値を設定します。\n\n```go\ntype decoder struct {\n\tsrc map[string]any\n}\n\nfunc (m decoder) ParseTag(name, tagStr, pathStr string, elemType reflect.Type) (tag any, err error) {\n\treturn runtimescan.BasicParseTag(name, tagStr, pathStr, elemType)\n}\n\nfunc (m *decoder) ExtractValue(tag any) (value any, err error) {\n\tt := tag.(*runtimescan.BasicTag)\n\tv, ok := m.src[t.Tag]\n\tif !ok {\n\t\treturn nil, runtimescan.Skip\n\t}\n\treturn v, nil\n}\n```\n\nこちらも、最後にユーザー向けのAPIの関数を定義します。\n\n```go\nfunc Decode(dest any, src map[string]any) error {\n\tdec := \u0026decoder{\n\t\tsrc: src,\n\t}\n\treturn runtimescan.Decode(dest, []string{\"map\"}, dec)\n}\n\n\n```\n\n#### 構造体を元にコード生成を行う(``staticscan/Scan()``)\n\nこちらはソースコードの構造体を静的解析します。\n\n#### 実装のヘルパー\n\nいくつか便利関数を提供しています。\n\n* ``runtimescan.BasicParseTag(name, tagStr, pathStr string, elemType reflect.Type)``\n\n  ``ParseTag()``で``encoding/json``のように出力先のキー名（省略時はフィールド名を小文字にしたもの）\n\n* ``runtimescan.Str2PrimitiveValue(v str)``\n\n  1やtrueなどの文字列表現からプリミティブを作成します。タグ中に文字列で書かれたプリミティブをデフォルト値などで使う場合に利用します。\n\n* ``runtimescan.IsPointerOfStruct(i any)``, ``runtimescan.IsPointerOfSliceOfStruct(i any)``, ``runtimescan.IsPointerOfSliceOfPointerOfStruct(i any)``\n\n  ``any``に渡されたポインタ型が``*struct``か``*[]struct``か``*[]*struct``かをそれぞれ判定します。``Decode()``を実装する時の型チェックに使います。\n\n* ``runtimescan.NewStructInstance(i any)``\n\n  引数で渡されたポインタ型を元に、インスタンスを生成して返します。引数は``*struct``か``*[]struct``か``*[]*struct``のいずれかを受け付け、``*struct``を返します。\n\n### 応用例\n\n#### 2つの構造体のインスタンスの比較\n\n``runtimescan.Encode()``をそれぞれのインスタンスごとに呼び、結果を``map``に入れてから比較することで構造体の比較が実現できます。\n\n#### 構造体のコピー\n\n``runtimescan.Encode()``をソースのインスタンスに対して呼び出し、``map``に一時的に値を入れてからそれを元に``runtimescan.Decode()``を呼び出すことで、構造体間でフィールドのコピーが行えます。\n\n### サンプル\n\n#### examples/restmap\n\n``runtimescan.Decode``を使い、HTTPリクエストの内容を構造体にマップします。\n次のような構造体を作成して、``restmap.Decode()``に``http.Request``とこの構造体のインスタンスをわたします。\n``body``のタグはリクエストの``Content-Type``ヘッダーを見て、``application/x-www-form-urlencoded``, ``multipart/form-data``, ``application/json``のいづれかであればパースしてデータを読み込みます。\nファイルのアップロードにも対応します。``rest:\"path:param\"`で、パスの一部から文字列を取り出しますが、今のところchi routerにのみ対応しています。\n\n```go\ntype Request struct {\n\tMethod  string                `rest:\"method\"`\n\tAuth    string                `rest:\"header:Authorization\"`\n\tTraceID string                `rest:\"cookie:trace-id\"`\n\tTitle   string                `rest:\"body:title-field\"`\n\tFile    multipart.File        `rest:\"body:file-field\"`\n\tHeader  *multipart.FileHeader `rest:\"body:file-field\"`\n\tCtx     context.Context       `rest:\"context\"`\n}\n```\n\n#### examples/binarypatternmatch\n\n``runtimescan.Decode``を使い、バイナリをロードします。タグに記述されたルールに従い、バイト列を読み込みアサインします。\n\n* ``数値``でビット数かバイト数を指定します\n* ``\u003c\u003c \u003e\u003e``で即値を指定します。文字列か数値が指定可能です。数値の場合は``/``でビット数かバイト数を指定します\n\n```go\ntype Image struct {\n\tHeader     string `bytes:\"\u003c\u003cHEAD\u003e\u003e\"`\n\tHeight     int32  `bytes:\"4\"`\n    Width      int32  `bytes:\"4\"`\n\tReadOnly   bool   `bits:\"1\"`\n\t_          byte   `bits:\"3\"`\n\tColorType  byte   `bits:\"4\"'`\n\tCheckDigit byte   `bits:\"\u003c\u003c0x5/6\u003e\u003e\"`\n}\n\nfunc main() {\n\tvar image Image\n\tf, _ := os.Open(\"imagefile\")\n    err := binarypatternmatch.Decode(\u0026image, f)\n}\n\n```\n\n## 静的なタグの取得\n\nソースコードを静的スキャンして構造体情報を取り出します。タグを元にしたコード生成のための機能です。\n\n``staticscan.Scan(rootPath, tagName: string) ([]staticscan.Struct, error)``\n\n## ライセンス\n\nApache2\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuture-architect%2Ftagscanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuture-architect%2Ftagscanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuture-architect%2Ftagscanner/lists"}