Fix for errors+failures parsing package.json

closes: #230

Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
This commit is contained in:
Toure Dunnon 2020-10-21 10:44:05 -04:00 committed by Toure
parent 931c796158
commit 15379d1075
6 changed files with 29 additions and 26 deletions

1
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/stereoscope v0.0.0-20200925184903-c82da54e98fe github.com/anchore/stereoscope v0.0.0-20200925184903-c82da54e98fe
github.com/apex/log v1.3.0
github.com/bmatcuk/doublestar v1.3.1 github.com/bmatcuk/doublestar v1.3.1
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize v1.0.0

View File

@ -27,6 +27,7 @@ type PackageJSON struct {
Homepage string `json:"homepage"` Homepage string `json:"homepage"`
Description string `json:"description"` Description string `json:"description"`
Dependencies map[string]string `json:"dependencies"` Dependencies map[string]string `json:"dependencies"`
Repository Repository `json:"repository"`
} }
type Author struct { type Author struct {
@ -35,36 +36,39 @@ type Author struct {
URL string `json:"url" mapstruct:"url"` URL string `json:"url" mapstruct:"url"`
} }
type Repository struct {
Type string `json:"type"`
URL string `json:"url"`
}
// match example: "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)"
// ---> name: "Isaac Z. Schlueter" email: "i@izs.me" url: "http://blog.izs.me"
var authorPattern = regexp.MustCompile(`^\s*(?P<name>[^<(]*)(\s+<(?P<email>.*)>)?(\s\((?P<url>.*)\))?\s*$`) var authorPattern = regexp.MustCompile(`^\s*(?P<name>[^<(]*)(\s+<(?P<email>.*)>)?(\s\((?P<url>.*)\))?\s*$`)
// This method implements the UnmarshalJSON interface to help normalize
// the json structure.
func (a *Author) UnmarshalJSON(b []byte) error { func (a *Author) UnmarshalJSON(b []byte) error {
var authorStr string var authorStr string
var fields map[string]string
var author Author
if err := json.Unmarshal(b, &authorStr); err != nil { if err := json.Unmarshal(b, &authorStr); err != nil {
// string parsing did not work, assume a map was given // string parsing did not work, assume a map was given
// for more information: https://docs.npmjs.com/files/package.json#people-fields-author-contributors // for more information: https://docs.npmjs.com/files/package.json#people-fields-author-contributors
var fields map[string]string
var author Author
if err := json.Unmarshal(b, &fields); err != nil { if err := json.Unmarshal(b, &fields); err != nil {
return fmt.Errorf("unable to parse package.json author: %w", err) return fmt.Errorf("unable to parse package.json author: %w", err)
} }
} else {
// parse out "name <email> (url)" into an Author struct
fields = internal.MatchCaptureGroups(authorPattern, authorStr)
}
// translate the map into a structure // translate the map into a structure
if err := mapstructure.Decode(fields, &author); err != nil { if err := mapstructure.Decode(fields, &author); err != nil {
return fmt.Errorf("unable to decode package.json author: %w", err) return fmt.Errorf("unable to decode package.json author: %w", err)
} }
*a = author
} else {
// parse out "name <email> (url)" into an Author struct
var fields = internal.MatchCaptureGroups(authorPattern, authorStr)
*a = Author{
Name: fields["name"],
Email: fields["email"],
URL: fields["url"],
}
}
if a.Name == "" { *a = author
return fmt.Errorf("package.json author name is empty")
}
return nil return nil
} }
@ -102,6 +106,7 @@ func parsePackageJSON(_ string, reader io.Reader) ([]pkg.Package, error) {
Metadata: pkg.NpmMetadata{ Metadata: pkg.NpmMetadata{
Author: p.Author.String(), Author: p.Author.String(),
Homepage: p.Homepage, Homepage: p.Homepage,
URL: p.Repository.URL,
}, },
}) })
} }

View File

@ -24,6 +24,7 @@ func TestParsePackageJSON(t *testing.T) {
Metadata: pkg.NpmMetadata{ Metadata: pkg.NpmMetadata{
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)", Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
Homepage: "https://docs.npmjs.com/", Homepage: "https://docs.npmjs.com/",
URL: "https://github.com/npm/cli",
}, },
}, },
}, },
@ -38,6 +39,7 @@ func TestParsePackageJSON(t *testing.T) {
Metadata: pkg.NpmMetadata{ Metadata: pkg.NpmMetadata{
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)", Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
Homepage: "https://docs.npmjs.com/", Homepage: "https://docs.npmjs.com/",
URL: "https://github.com/npm/cli",
}, },
}, },
}, },
@ -62,6 +64,7 @@ func TestParsePackageJSON(t *testing.T) {
} }
for _, d := range deep.Equal(actual[0], test.ExpectedPkg) { for _, d := range deep.Equal(actual[0], test.ExpectedPkg) {
t.Errorf("diff: %+v", d) t.Errorf("diff: %+v", d)
} }
}) })

View File

@ -8,5 +8,9 @@
"email": "i@izs.me", "email": "i@izs.me",
"url": "http://blog.izs.me" "url": "http://blog.izs.me"
}, },
"repository": {
"type": "git",
"url": "https://github.com/npm/cli"
},
"license": "Artistic-2.0" "license": "Artistic-2.0"
} }

View File

@ -1,11 +0,0 @@
package pkg
type MetadataType string
const (
UnknownMetadataType MetadataType = "UnknownMetadata"
ApkMetadataType MetadataType = "apk-metadata"
DpkgMetadataType MetadataType = "dpkg-metadata"
GemgMetadataType MetadataType = "gem-metadata"
RpmdbMetadataType MetadataType = "rpmdb-metadata"
)

View File

@ -9,4 +9,5 @@ type NpmMetadata struct {
License string `mapstructure:"license" json:"license"` License string `mapstructure:"license" json:"license"`
Homepage string `mapstructure:"homepage" json:"homepage"` Homepage string `mapstructure:"homepage" json:"homepage"`
Description string `mapstructure:"description" json:"description"` Description string `mapstructure:"description" json:"description"`
URL string `mapstructure:"url" json:"url"`
} }