github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/internal/packagemetadata/names.go (about) 1 package packagemetadata 2 3 import ( 4 "reflect" 5 "strings" 6 7 "github.com/anchore/syft/syft/pkg" 8 ) 9 10 type jsonType struct { 11 ty any 12 name string 13 legacyNames []string 14 noLookupLegacyName string // legacy name that conflict with other types, thus should not affect the lookup 15 } 16 17 func jsonNames(ty any, name string, legacyNames ...string) jsonType { 18 return jsonType{ 19 ty: ty, 20 name: name, 21 legacyNames: expandLegacyNameVariants(legacyNames...), 22 } 23 } 24 25 func jsonNamesWithoutLookup(ty any, name string, noLookupLegacyName string) jsonType { 26 return jsonType{ 27 ty: ty, 28 name: name, 29 noLookupLegacyName: noLookupLegacyName, 30 } 31 } 32 33 type jsonTypeMapping struct { 34 typeToName map[reflect.Type]string 35 typeToLegacyName map[reflect.Type]string 36 nameToType map[string]reflect.Type 37 } 38 39 func makeJSONTypes(types ...jsonType) jsonTypeMapping { 40 out := jsonTypeMapping{ 41 typeToName: make(map[reflect.Type]string), 42 typeToLegacyName: make(map[reflect.Type]string), 43 nameToType: make(map[string]reflect.Type), 44 } 45 for _, t := range types { 46 typ := reflect.TypeOf(t.ty) 47 out.typeToName[typ] = t.name 48 if len(t.noLookupLegacyName) > 0 { 49 out.typeToLegacyName[typ] = t.noLookupLegacyName 50 } else if len(t.legacyNames) > 0 { 51 out.typeToLegacyName[typ] = t.legacyNames[0] 52 } 53 out.nameToType[strings.ToLower(t.name)] = typ 54 for _, name := range t.legacyNames { 55 out.nameToType[strings.ToLower(name)] = typ 56 } 57 } 58 return out 59 } 60 61 // jsonNameFromType is lookup of all known package metadata types to their current JSON name and all previously known aliases. 62 // It is important that if a name needs to change that the old name is kept in this map (as an alias) for backwards 63 // compatibility to support decoding older JSON documents. 64 var jsonTypes = makeJSONTypes( 65 jsonNames(pkg.AlpmDBEntry{}, "alpm-db-entry", "AlpmMetadata"), 66 jsonNames(pkg.ApkDBEntry{}, "apk-db-entry", "ApkMetadata"), 67 jsonNames(pkg.BinarySignature{}, "binary-signature", "BinaryMetadata"), 68 jsonNames(pkg.CocoaPodfileLockEntry{}, "cocoa-podfile-lock-entry", "CocoapodsMetadataType"), 69 jsonNames(pkg.ConanV1LockEntry{}, "c-conan-lock-entry", "ConanLockMetadataType"), 70 jsonNames(pkg.ConanV2LockEntry{}, "c-conan-lock-v2-entry"), 71 jsonNames(pkg.ConanfileEntry{}, "c-conan-file-entry", "ConanMetadataType"), 72 jsonNames(pkg.ConaninfoEntry{}, "c-conan-info-entry"), 73 jsonNames(pkg.DartPubspecLockEntry{}, "dart-pubspec-lock-entry", "DartPubMetadata"), 74 jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"), 75 jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"), 76 jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"), 77 jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"), 78 jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"), 79 jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"), 80 jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"), 81 jsonNames(pkg.HackageStackYamlLockEntry{}, "haskell-hackage-stack-lock-entry", "HackageMetadataType"), 82 jsonNamesWithoutLookup(pkg.HackageStackYamlEntry{}, "haskell-hackage-stack-entry", "HackageMetadataType"), // the legacy value is split into two types, where the other is preferred 83 jsonNames(pkg.JavaArchive{}, "java-archive", "JavaMetadata"), 84 jsonNames(pkg.MicrosoftKbPatch{}, "microsoft-kb-patch", "KbPatchMetadata"), 85 jsonNames(pkg.LinuxKernel{}, "linux-kernel-archive", "LinuxKernel"), 86 jsonNames(pkg.LinuxKernelModule{}, "linux-kernel-module", "LinuxKernelModule"), 87 jsonNames(pkg.ElixirMixLockEntry{}, "elixir-mix-lock-entry", "MixLockMetadataType"), 88 jsonNames(pkg.NixStoreEntry{}, "nix-store-entry", "NixStoreMetadata"), 89 jsonNames(pkg.NpmPackage{}, "javascript-npm-package", "NpmPackageJsonMetadata"), 90 jsonNames(pkg.NpmPackageLockEntry{}, "javascript-npm-package-lock-entry", "NpmPackageLockJsonMetadata"), 91 jsonNames(pkg.YarnLockEntry{}, "javascript-yarn-lock-entry", "YarnLockJsonMetadata"), 92 jsonNames(pkg.PhpComposerLockEntry{}, "php-composer-lock-entry", "PhpComposerJsonMetadata"), 93 jsonNamesWithoutLookup(pkg.PhpComposerInstalledEntry{}, "php-composer-installed-entry", "PhpComposerJsonMetadata"), // the legacy value is split into two types, where the other is preferred 94 jsonNames(pkg.PhpPeclEntry{}, "php-pecl-entry", "PhpPeclMetadata"), 95 jsonNames(pkg.PortageEntry{}, "portage-db-entry", "PortageMetadata"), 96 jsonNames(pkg.PythonPackage{}, "python-package", "PythonPackageMetadata"), 97 jsonNames(pkg.PythonPipfileLockEntry{}, "python-pipfile-lock-entry", "PythonPipfileLockMetadata"), 98 jsonNames(pkg.PythonPoetryLockEntry{}, "python-poetry-lock-entry", "PythonPoetryLockMetadata"), 99 jsonNames(pkg.PythonRequirementsEntry{}, "python-pip-requirements-entry", "PythonRequirementsMetadata"), 100 jsonNames(pkg.ErlangRebarLockEntry{}, "erlang-rebar-lock-entry", "RebarLockMetadataType"), 101 jsonNames(pkg.RDescription{}, "r-description", "RDescriptionFileMetadataType"), 102 jsonNames(pkg.RpmDBEntry{}, "rpm-db-entry", "RpmMetadata", "RpmdbMetadata"), 103 jsonNamesWithoutLookup(pkg.RpmArchive{}, "rpm-archive", "RpmMetadata"), // the legacy value is split into two types, where the other is preferred 104 jsonNames(pkg.SwiftPackageManagerResolvedEntry{}, "swift-package-manager-lock-entry", "SwiftPackageManagerMetadata"), 105 jsonNames(pkg.RustCargoLockEntry{}, "rust-cargo-lock-entry", "RustCargoPackageMetadata"), 106 jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred 107 jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"), 108 ) 109 110 func expandLegacyNameVariants(names ...string) []string { 111 var candidates []string 112 for _, name := range names { 113 candidates = append(candidates, name) 114 if strings.HasSuffix(name, "MetadataType") { 115 candidates = append(candidates, strings.TrimSuffix(name, "Type")) 116 } else if strings.HasSuffix(name, "Metadata") { 117 candidates = append(candidates, name+"Type") 118 } 119 } 120 return candidates 121 } 122 123 func AllTypeNames() []string { 124 names := make([]string, 0) 125 for _, t := range AllTypes() { 126 names = append(names, reflect.TypeOf(t).Name()) 127 } 128 return names 129 } 130 131 func JSONName(metadata any) string { 132 if name, exists := jsonTypes.typeToName[reflect.TypeOf(metadata)]; exists { 133 return name 134 } 135 return "" 136 } 137 138 func JSONLegacyName(metadata any) string { 139 if name, exists := jsonTypes.typeToLegacyName[reflect.TypeOf(metadata)]; exists { 140 return name 141 } 142 return JSONName(metadata) 143 } 144 145 func ReflectTypeFromJSONName(name string) reflect.Type { 146 name = strings.ToLower(name) 147 return jsonTypes.nameToType[name] 148 }