vendor: github.com/go-viper/mapstructure/v2 v2.5.0
full diff: https://github.com/go-viper/mapstructure/compare/v2.4.0...v2.5.0 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -138,7 +138,7 @@ require (
|
|||||||
github.com/go-openapi/swag/typeutils v0.25.3 // indirect
|
github.com/go-openapi/swag/typeutils v0.25.3 // indirect
|
||||||
github.com/go-openapi/swag/yamlutils v0.25.3 // indirect
|
github.com/go-openapi/swag/yamlutils v0.25.3 // indirect
|
||||||
github.com/go-openapi/validate v0.25.1 // indirect
|
github.com/go-openapi/validate v0.25.1 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
|||||||
@@ -271,8 +271,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
|||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
|
|||||||
+3
@@ -19,3 +19,6 @@ indent_size = 2
|
|||||||
|
|
||||||
[.golangci.yaml]
|
[.golangci.yaml]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
[devenv.yaml]
|
||||||
|
indent_size = 2
|
||||||
|
|||||||
+7
-4
@@ -1,4 +1,7 @@
|
|||||||
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
|
#!/usr/bin/env bash
|
||||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
|
|
||||||
fi
|
export DIRENV_WARN_TIMEOUT=20s
|
||||||
use flake . --impure
|
|
||||||
|
eval "$(devenv direnvrc)"
|
||||||
|
|
||||||
|
use devenv
|
||||||
|
|||||||
+7
-3
@@ -1,6 +1,10 @@
|
|||||||
/.devenv/
|
|
||||||
/.direnv/
|
|
||||||
/.pre-commit-config.yaml
|
|
||||||
/bin/
|
/bin/
|
||||||
/build/
|
/build/
|
||||||
/var/
|
/var/
|
||||||
|
|
||||||
|
# Devenv
|
||||||
|
.devenv*
|
||||||
|
devenv.local.nix
|
||||||
|
devenv.local.yaml
|
||||||
|
.direnv
|
||||||
|
.pre-commit-config.yaml
|
||||||
|
|||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"devenv": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"lastModified": 1765288076,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"rev": "93c055af1e8fcac49251f1b2e1c57f78620ad351",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765121682,
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"git-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765016596,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"git-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1762808025,
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764580874,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"ref": "rolling",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"devenv": "devenv",
|
||||||
|
"git-hooks": "git-hooks",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"pre-commit-hooks": [
|
||||||
|
"git-hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
languages = {
|
||||||
|
go.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = with pkgs; [
|
||||||
|
golangci-lint
|
||||||
|
];
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
|
||||||
|
inputs:
|
||||||
|
nixpkgs:
|
||||||
|
url: github:cachix/devenv-nixpkgs/rolling
|
||||||
-294
@@ -1,294 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"cachix": {
|
|
||||||
"inputs": {
|
|
||||||
"devenv": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"git-hooks": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1742042642,
|
|
||||||
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "cachix",
|
|
||||||
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"ref": "latest",
|
|
||||||
"repo": "cachix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devenv": {
|
|
||||||
"inputs": {
|
|
||||||
"cachix": "cachix",
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"git-hooks": "git-hooks",
|
|
||||||
"nix": "nix",
|
|
||||||
"nixpkgs": "nixpkgs_3"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1744876578,
|
|
||||||
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1733328505,
|
|
||||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"devenv",
|
|
||||||
"nix",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712014858,
|
|
||||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts_2": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1743550720,
|
|
||||||
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-hooks": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1742649964,
|
|
||||||
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "git-hooks.nix",
|
|
||||||
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "git-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gitignore": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"git-hooks",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709087332,
|
|
||||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libgit2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1697646580,
|
|
||||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"libgit2": "libgit2",
|
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"nixpkgs-23-11": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"nixpkgs-regression": [
|
|
||||||
"devenv"
|
|
||||||
],
|
|
||||||
"pre-commit-hooks": [
|
|
||||||
"devenv"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1741798497,
|
|
||||||
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"ref": "devenv-2.24",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1733212471,
|
|
||||||
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1743296961,
|
|
||||||
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1717432640,
|
|
||||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "release-24.05",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1733477122,
|
|
||||||
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"ref": "rolling",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1744536153,
|
|
||||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"devenv": "devenv",
|
|
||||||
"flake-parts": "flake-parts_2",
|
|
||||||
"nixpkgs": "nixpkgs_4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
-46
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
|
||||||
devenv.url = "github:cachix/devenv";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs =
|
|
||||||
inputs@{ flake-parts, ... }:
|
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
|
||||||
imports = [
|
|
||||||
inputs.devenv.flakeModule
|
|
||||||
];
|
|
||||||
|
|
||||||
systems = [
|
|
||||||
"x86_64-linux"
|
|
||||||
"x86_64-darwin"
|
|
||||||
"aarch64-darwin"
|
|
||||||
];
|
|
||||||
|
|
||||||
perSystem =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
rec {
|
|
||||||
devenv.shells = {
|
|
||||||
default = {
|
|
||||||
languages = {
|
|
||||||
go.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
pre-commit.hooks = {
|
|
||||||
nixpkgs-fmt.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
packages = with pkgs; [
|
|
||||||
golangci-lint
|
|
||||||
];
|
|
||||||
|
|
||||||
# https://github.com/cachix/devenv/issues/528#issuecomment-1556108767
|
|
||||||
containers = pkgs.lib.mkForce { };
|
|
||||||
};
|
|
||||||
|
|
||||||
ci = devenv.shells.default;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+284
-48
@@ -173,6 +173,25 @@
|
|||||||
// Public: "I made it through!"
|
// Public: "I made it through!"
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// # Custom Decoding with Unmarshaler
|
||||||
|
//
|
||||||
|
// Types can implement the Unmarshaler interface to control their own decoding. The interface
|
||||||
|
// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an
|
||||||
|
// alternative or companion to a DecodeHook.
|
||||||
|
//
|
||||||
|
// type TrimmedString string
|
||||||
|
//
|
||||||
|
// func (t *TrimmedString) UnmarshalMapstructure(input any) error {
|
||||||
|
// str, ok := input.(string)
|
||||||
|
// if !ok {
|
||||||
|
// return fmt.Errorf("expected string, got %T", input)
|
||||||
|
// }
|
||||||
|
// *t = TrimmedString(strings.TrimSpace(str))
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See the Unmarshaler interface documentation for more details.
|
||||||
|
//
|
||||||
// # Other Configuration
|
// # Other Configuration
|
||||||
//
|
//
|
||||||
// mapstructure is highly configurable. See the DecoderConfig struct
|
// mapstructure is highly configurable. See the DecoderConfig struct
|
||||||
@@ -218,6 +237,17 @@ type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error)
|
|||||||
// values.
|
// values.
|
||||||
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)
|
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)
|
||||||
|
|
||||||
|
// Unmarshaler is the interface implemented by types that can unmarshal
|
||||||
|
// themselves. UnmarshalMapstructure receives the input data (potentially
|
||||||
|
// transformed by DecodeHook) and should populate the receiver with the
|
||||||
|
// decoded values.
|
||||||
|
//
|
||||||
|
// The Unmarshaler interface takes precedence over the default decoding
|
||||||
|
// logic for any type (structs, slices, maps, primitives, etc.).
|
||||||
|
type Unmarshaler interface {
|
||||||
|
UnmarshalMapstructure(any) error
|
||||||
|
}
|
||||||
|
|
||||||
// DecoderConfig is the configuration that is used to create a new decoder
|
// DecoderConfig is the configuration that is used to create a new decoder
|
||||||
// and allows customization of various aspects of decoding.
|
// and allows customization of various aspects of decoding.
|
||||||
type DecoderConfig struct {
|
type DecoderConfig struct {
|
||||||
@@ -281,6 +311,13 @@ type DecoderConfig struct {
|
|||||||
// }
|
// }
|
||||||
Squash bool
|
Squash bool
|
||||||
|
|
||||||
|
// Deep will map structures in slices instead of copying them
|
||||||
|
//
|
||||||
|
// type Parent struct {
|
||||||
|
// Children []Child `mapstructure:",deep"`
|
||||||
|
// }
|
||||||
|
Deep bool
|
||||||
|
|
||||||
// Metadata is the struct that will contain extra metadata about
|
// Metadata is the struct that will contain extra metadata about
|
||||||
// the decoding. If this is nil, then no metadata will be tracked.
|
// the decoding. If this is nil, then no metadata will be tracked.
|
||||||
Metadata *Metadata
|
Metadata *Metadata
|
||||||
@@ -290,9 +327,15 @@ type DecoderConfig struct {
|
|||||||
Result any
|
Result any
|
||||||
|
|
||||||
// The tag name that mapstructure reads for field names. This
|
// The tag name that mapstructure reads for field names. This
|
||||||
// defaults to "mapstructure"
|
// defaults to "mapstructure". Multiple tag names can be specified
|
||||||
|
// as a comma-separated list (e.g., "yaml,json"), and the first
|
||||||
|
// matching non-empty tag will be used.
|
||||||
TagName string
|
TagName string
|
||||||
|
|
||||||
|
// RootName specifies the name to use for the root element in error messages. For example:
|
||||||
|
// '<rootName>' has unset fields: <fieldName>
|
||||||
|
RootName string
|
||||||
|
|
||||||
// The option of the value in the tag that indicates a field should
|
// The option of the value in the tag that indicates a field should
|
||||||
// be squashed. This defaults to "squash".
|
// be squashed. This defaults to "squash".
|
||||||
SquashTagOption string
|
SquashTagOption string
|
||||||
@@ -304,11 +347,34 @@ type DecoderConfig struct {
|
|||||||
// MatchName is the function used to match the map key to the struct
|
// MatchName is the function used to match the map key to the struct
|
||||||
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
||||||
// to implement case-sensitive tag values, support snake casing, etc.
|
// to implement case-sensitive tag values, support snake casing, etc.
|
||||||
|
//
|
||||||
|
// MatchName is used as a fallback comparison when the direct key lookup fails.
|
||||||
|
// See also MapFieldName for transforming field names before lookup.
|
||||||
MatchName func(mapKey, fieldName string) bool
|
MatchName func(mapKey, fieldName string) bool
|
||||||
|
|
||||||
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
|
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
|
||||||
// even if the input is nil. This can be used to provide default values.
|
// even if the input is nil. This can be used to provide default values.
|
||||||
DecodeNil bool
|
DecodeNil bool
|
||||||
|
|
||||||
|
// MapFieldName is the function used to convert the struct field name to the map's key name.
|
||||||
|
//
|
||||||
|
// This is useful for automatically converting between naming conventions without
|
||||||
|
// explicitly tagging each field. For example, to convert Go's PascalCase field names
|
||||||
|
// to snake_case map keys:
|
||||||
|
//
|
||||||
|
// MapFieldName: func(s string) string {
|
||||||
|
// return strcase.ToSnake(s)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// When decoding from a map to a struct, the transformed field name is used for
|
||||||
|
// the initial lookup. If not found, MatchName is used as a fallback comparison.
|
||||||
|
// Explicit struct tags always take precedence over MapFieldName.
|
||||||
|
MapFieldName func(string) string
|
||||||
|
|
||||||
|
// DisableUnmarshaler, if set to true, disables the use of the Unmarshaler
|
||||||
|
// interface. Types implementing Unmarshaler will be decoded using the
|
||||||
|
// standard struct decoding logic instead.
|
||||||
|
DisableUnmarshaler bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Decoder takes a raw interface value and turns it into structured
|
// A Decoder takes a raw interface value and turns it into structured
|
||||||
@@ -445,6 +511,12 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
|||||||
config.MatchName = strings.EqualFold
|
config.MatchName = strings.EqualFold
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.MapFieldName == nil {
|
||||||
|
config.MapFieldName = func(s string) string {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result := &Decoder{
|
result := &Decoder{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
@@ -458,7 +530,7 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
|||||||
// Decode decodes the given raw interface to the target pointer specified
|
// Decode decodes the given raw interface to the target pointer specified
|
||||||
// by the configuration.
|
// by the configuration.
|
||||||
func (d *Decoder) Decode(input any) error {
|
func (d *Decoder) Decode(input any) error {
|
||||||
err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
|
err := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem())
|
||||||
|
|
||||||
// Retain some of the original behavior when multiple errors ocurr
|
// Retain some of the original behavior when multiple errors ocurr
|
||||||
var joinedErr interface{ Unwrap() []error }
|
var joinedErr interface{ Unwrap() []error }
|
||||||
@@ -540,36 +612,50 @@ func (d *Decoder) decode(name string, input any, outVal reflect.Value) error {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
addMetaKey := true
|
addMetaKey := true
|
||||||
switch outputKind {
|
|
||||||
case reflect.Bool:
|
// Check if the target implements Unmarshaler and use it if not disabled
|
||||||
err = d.decodeBool(name, input, outVal)
|
unmarshaled := false
|
||||||
case reflect.Interface:
|
if !d.config.DisableUnmarshaler {
|
||||||
err = d.decodeBasic(name, input, outVal)
|
if unmarshaler, ok := getUnmarshaler(outVal); ok {
|
||||||
case reflect.String:
|
if err = unmarshaler.UnmarshalMapstructure(input); err != nil {
|
||||||
err = d.decodeString(name, input, outVal)
|
err = newDecodeError(name, err)
|
||||||
case reflect.Int:
|
}
|
||||||
err = d.decodeInt(name, input, outVal)
|
unmarshaled = true
|
||||||
case reflect.Uint:
|
}
|
||||||
err = d.decodeUint(name, input, outVal)
|
}
|
||||||
case reflect.Float32:
|
|
||||||
err = d.decodeFloat(name, input, outVal)
|
if !unmarshaled {
|
||||||
case reflect.Complex64:
|
switch outputKind {
|
||||||
err = d.decodeComplex(name, input, outVal)
|
case reflect.Bool:
|
||||||
case reflect.Struct:
|
err = d.decodeBool(name, input, outVal)
|
||||||
err = d.decodeStruct(name, input, outVal)
|
case reflect.Interface:
|
||||||
case reflect.Map:
|
err = d.decodeBasic(name, input, outVal)
|
||||||
err = d.decodeMap(name, input, outVal)
|
case reflect.String:
|
||||||
case reflect.Ptr:
|
err = d.decodeString(name, input, outVal)
|
||||||
addMetaKey, err = d.decodePtr(name, input, outVal)
|
case reflect.Int:
|
||||||
case reflect.Slice:
|
err = d.decodeInt(name, input, outVal)
|
||||||
err = d.decodeSlice(name, input, outVal)
|
case reflect.Uint:
|
||||||
case reflect.Array:
|
err = d.decodeUint(name, input, outVal)
|
||||||
err = d.decodeArray(name, input, outVal)
|
case reflect.Float32:
|
||||||
case reflect.Func:
|
err = d.decodeFloat(name, input, outVal)
|
||||||
err = d.decodeFunc(name, input, outVal)
|
case reflect.Complex64:
|
||||||
default:
|
err = d.decodeComplex(name, input, outVal)
|
||||||
// If we reached this point then we weren't able to decode it
|
case reflect.Struct:
|
||||||
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
|
err = d.decodeStruct(name, input, outVal)
|
||||||
|
case reflect.Map:
|
||||||
|
err = d.decodeMap(name, input, outVal)
|
||||||
|
case reflect.Ptr:
|
||||||
|
addMetaKey, err = d.decodePtr(name, input, outVal)
|
||||||
|
case reflect.Slice:
|
||||||
|
err = d.decodeSlice(name, input, outVal)
|
||||||
|
case reflect.Array:
|
||||||
|
err = d.decodeArray(name, input, outVal)
|
||||||
|
case reflect.Func:
|
||||||
|
err = d.decodeFunc(name, input, outVal)
|
||||||
|
default:
|
||||||
|
// If we reached this point then we weren't able to decode it
|
||||||
|
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reached here, then we successfully decoded SOMETHING, so
|
// If we reached here, then we successfully decoded SOMETHING, so
|
||||||
@@ -668,7 +754,7 @@ func (d *Decoder) decodeString(name string, data any, val reflect.Value) error {
|
|||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
var uints []uint8
|
var uints []uint8
|
||||||
if dataKind == reflect.Array {
|
if dataKind == reflect.Array {
|
||||||
uints = make([]uint8, dataVal.Len(), dataVal.Len())
|
uints = make([]uint8, dataVal.Len())
|
||||||
for i := range uints {
|
for i := range uints {
|
||||||
uints[i] = dataVal.Index(i).Interface().(uint8)
|
uints[i] = dataVal.Index(i).Interface().(uint8)
|
||||||
}
|
}
|
||||||
@@ -1060,8 +1146,8 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
tagValue := f.Tag.Get(d.config.TagName)
|
tagValue, _ := getTagValue(f, d.config.TagName)
|
||||||
keyName := f.Name
|
keyName := d.config.MapFieldName(f.Name)
|
||||||
|
|
||||||
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
||||||
continue
|
continue
|
||||||
@@ -1070,6 +1156,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
// If Squash is set in the config, we squash the field down.
|
// If Squash is set in the config, we squash the field down.
|
||||||
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
|
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
|
||||||
|
|
||||||
|
// If Deep is set in the config, set as default value.
|
||||||
|
deep := d.config.Deep
|
||||||
|
|
||||||
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
|
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
|
||||||
|
|
||||||
// Determine the name of the key in the map
|
// Determine the name of the key in the map
|
||||||
@@ -1078,12 +1167,12 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If "omitempty" is specified in the tag, it ignores empty values.
|
// If "omitempty" is specified in the tag, it ignores empty values.
|
||||||
if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) {
|
if strings.Contains(tagValue[index+1:], "omitempty") && isEmptyValue(v) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "omitzero" is specified in the tag, it ignores zero values.
|
// If "omitzero" is specified in the tag, it ignores zero values.
|
||||||
if strings.Index(tagValue[index+1:], "omitzero") != -1 && v.IsZero() {
|
if strings.Contains(tagValue[index+1:], "omitzero") && v.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1103,7 +1192,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if strings.Index(tagValue[index+1:], "remain") != -1 {
|
if strings.Contains(tagValue[index+1:], "remain") {
|
||||||
if v.Kind() != reflect.Map {
|
if v.Kind() != reflect.Map {
|
||||||
return newDecodeError(
|
return newDecodeError(
|
||||||
name+"."+f.Name,
|
name+"."+f.Name,
|
||||||
@@ -1118,6 +1207,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deep = deep || strings.Contains(tagValue[index+1:], "deep")
|
||||||
|
|
||||||
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
|
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
|
||||||
keyName = keyNameTagValue
|
keyName = keyNameTagValue
|
||||||
}
|
}
|
||||||
@@ -1164,6 +1256,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
|||||||
valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
|
valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if deep {
|
||||||
|
var childType reflect.Type
|
||||||
|
switch v.Type().Elem().Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
childType = reflect.TypeOf(map[string]any{})
|
||||||
|
default:
|
||||||
|
childType = v.Type().Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
sType := reflect.SliceOf(childType)
|
||||||
|
|
||||||
|
addrVal := reflect.New(sType)
|
||||||
|
|
||||||
|
vSlice := reflect.MakeSlice(sType, v.Len(), v.Cap())
|
||||||
|
|
||||||
|
if v.Len() > 0 {
|
||||||
|
reflect.Indirect(addrVal).Set(vSlice)
|
||||||
|
|
||||||
|
err := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vSlice = reflect.Indirect(addrVal)
|
||||||
|
|
||||||
|
valMap.SetMapIndex(reflect.ValueOf(keyName), vSlice)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// When deep mapping is not needed, fallthrough to normal copy
|
||||||
|
fallthrough
|
||||||
|
|
||||||
default:
|
default:
|
||||||
valMap.SetMapIndex(reflect.ValueOf(keyName), v)
|
valMap.SetMapIndex(reflect.ValueOf(keyName), v)
|
||||||
}
|
}
|
||||||
@@ -1471,7 +1598,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
|||||||
remain := false
|
remain := false
|
||||||
|
|
||||||
// We always parse the tags cause we're looking for other tags too
|
// We always parse the tags cause we're looking for other tags too
|
||||||
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
tagParts := getTagParts(fieldType, d.config.TagName)
|
||||||
|
if len(tagParts) == 0 {
|
||||||
|
tagParts = []string{""}
|
||||||
|
}
|
||||||
for _, tag := range tagParts[1:] {
|
for _, tag := range tagParts[1:] {
|
||||||
if tag == d.config.SquashTagOption {
|
if tag == d.config.SquashTagOption {
|
||||||
squash = true
|
squash = true
|
||||||
@@ -1492,6 +1622,18 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
|||||||
if !fieldVal.IsNil() {
|
if !fieldVal.IsNil() {
|
||||||
structs = append(structs, fieldVal.Elem().Elem())
|
structs = append(structs, fieldVal.Elem().Elem())
|
||||||
}
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if fieldVal.Type().Elem().Kind() == reflect.Struct {
|
||||||
|
if fieldVal.IsNil() {
|
||||||
|
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
|
||||||
|
}
|
||||||
|
structs = append(structs, fieldVal.Elem())
|
||||||
|
} else {
|
||||||
|
errs = append(errs, newDecodeError(
|
||||||
|
name+"."+fieldType.Name,
|
||||||
|
fmt.Errorf("unsupported type for squashed pointer: %s", fieldVal.Type().Elem().Kind()),
|
||||||
|
))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
errs = append(errs, newDecodeError(
|
errs = append(errs, newDecodeError(
|
||||||
name+"."+fieldType.Name,
|
name+"."+fieldType.Name,
|
||||||
@@ -1516,13 +1658,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
|||||||
field, fieldValue := f.field, f.val
|
field, fieldValue := f.field, f.val
|
||||||
fieldName := field.Name
|
fieldName := field.Name
|
||||||
|
|
||||||
tagValue := field.Tag.Get(d.config.TagName)
|
tagValue, _ := getTagValue(field, d.config.TagName)
|
||||||
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tagValue = strings.SplitN(tagValue, ",", 2)[0]
|
tagValue = strings.SplitN(tagValue, ",", 2)[0]
|
||||||
if tagValue != "" {
|
if tagValue != "" {
|
||||||
fieldName = tagValue
|
fieldName = tagValue
|
||||||
|
} else {
|
||||||
|
fieldName = d.config.MapFieldName(fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawMapKey := reflect.ValueOf(fieldName)
|
rawMapKey := reflect.ValueOf(fieldName)
|
||||||
@@ -1605,8 +1749,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
|||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
// Improve error message when name is empty by showing the target struct type
|
||||||
|
// in the case where it is empty for embedded structs.
|
||||||
|
errorName := name
|
||||||
|
if errorName == "" {
|
||||||
|
errorName = val.Type().String()
|
||||||
|
}
|
||||||
errs = append(errs, newDecodeError(
|
errs = append(errs, newDecodeError(
|
||||||
name,
|
errorName,
|
||||||
fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")),
|
fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -1692,7 +1842,7 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
|
|||||||
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
|
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
|
if checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1700,13 +1850,99 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
|
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
|
||||||
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
|
if v.Kind() != reflect.Ptr {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
deref := v.Elem()
|
|
||||||
derefT := deref.Type()
|
switch v.Elem().Kind() {
|
||||||
if isStructTypeConvertibleToMap(derefT, true, tagName) {
|
case reflect.Slice:
|
||||||
return deref
|
return v.Elem()
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
deref := v.Elem()
|
||||||
|
derefT := deref.Type()
|
||||||
|
if isStructTypeConvertibleToMap(derefT, true, tagName) {
|
||||||
|
return deref
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
|
||||||
|
default:
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
return v
|
}
|
||||||
|
|
||||||
|
func hasAnyTag(field reflect.StructField, tagName string) bool {
|
||||||
|
_, ok := getTagValue(field, tagName)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTagParts(field reflect.StructField, tagName string) []string {
|
||||||
|
tagValue, ok := getTagValue(field, tagName)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.Split(tagValue, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTagValue(field reflect.StructField, tagName string) (string, bool) {
|
||||||
|
for _, name := range splitTagNames(tagName) {
|
||||||
|
if tag := field.Tag.Get(name); tag != "" {
|
||||||
|
return tag, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitTagNames(tagName string) []string {
|
||||||
|
if tagName == "" {
|
||||||
|
return []string{"mapstructure"}
|
||||||
|
}
|
||||||
|
parts := strings.Split(tagName, ",")
|
||||||
|
result := make([]string, 0, len(parts))
|
||||||
|
|
||||||
|
for _, name := range parts {
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
if name != "" {
|
||||||
|
result = append(result, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalerType is cached for performance
|
||||||
|
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||||
|
|
||||||
|
// getUnmarshaler checks if the value implements Unmarshaler and returns
|
||||||
|
// the Unmarshaler and a boolean indicating if it was found. It handles both
|
||||||
|
// pointer and value receivers.
|
||||||
|
func getUnmarshaler(val reflect.Value) (Unmarshaler, bool) {
|
||||||
|
// Skip invalid or nil values
|
||||||
|
if !val.IsValid() {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Pointer, reflect.Interface:
|
||||||
|
if val.IsNil() {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check pointer receiver first (most common case)
|
||||||
|
if val.CanAddr() {
|
||||||
|
ptrVal := val.Addr()
|
||||||
|
// Quick check: if no methods, can't implement any interface
|
||||||
|
if ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) {
|
||||||
|
return ptrVal.Interface().(Unmarshaler), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check value receiver
|
||||||
|
// Quick check: if no methods, can't implement any interface
|
||||||
|
if val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) {
|
||||||
|
return val.Interface().(Unmarshaler), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -439,7 +439,7 @@ github.com/go-openapi/swag/yamlutils
|
|||||||
# github.com/go-openapi/validate v0.25.1
|
# github.com/go-openapi/validate v0.25.1
|
||||||
## explicit; go 1.24.0
|
## explicit; go 1.24.0
|
||||||
github.com/go-openapi/validate
|
github.com/go-openapi/validate
|
||||||
# github.com/go-viper/mapstructure/v2 v2.4.0
|
# github.com/go-viper/mapstructure/v2 v2.5.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/go-viper/mapstructure/v2
|
github.com/go-viper/mapstructure/v2
|
||||||
github.com/go-viper/mapstructure/v2/internal/errors
|
github.com/go-viper/mapstructure/v2/internal/errors
|
||||||
|
|||||||
Reference in New Issue
Block a user