Enhance Npm Resolver: support recording license contents (#71)

diff --git a/pkg/deps/npm.go b/pkg/deps/npm.go
index fc51930..00bf2c5 100644
--- a/pkg/deps/npm.go
+++ b/pkg/deps/npm.go
@@ -85,12 +85,12 @@
 	// Walk through each package's root directory to resolve licenses
 	// Resolve from a package's package.json file or its license file
 	for _, pkg := range pkgs {
-		if err := resolver.ResolvePackageLicense(pkg.Name, pkg.Path, report); err != nil {
-			logger.Log.Warnln("Failed to resolve the license of dependency:", pkg.Name, err)
-			report.Skip(&Result{
-				Dependency:    pkg.Name,
-				LicenseSpdxID: Unknown,
-			})
+		if result := resolver.ResolvePackageLicense(pkg.Name, pkg.Path); result.LicenseSpdxID != "" {
+			report.Resolve(result)
+		} else {
+			result.LicenseSpdxID = Unknown
+			report.Skip(result)
+			logger.Log.Warnln("Failed to resolve the license of dependency:", pkg.Name, result.ResolveErrors)
 		}
 	}
 	return nil
@@ -184,47 +184,43 @@
 // ResolvePackageLicense resolves the licenses of the given packages.
 // First, try to find and parse the package's package.json file to check the license file
 // If the previous step fails, then try to identify the package's LICENSE file
-func (resolver *NpmResolver) ResolvePackageLicense(pkgName, pkgPath string, report *Report) error {
-	var resolveErrs error
-	expectedPkgFile := filepath.Join(pkgPath, PkgFileName)
-	lcs, err := resolver.ResolvePkgFile(expectedPkgFile)
-	if err == nil {
-		report.Resolve(&Result{
-			Dependency:    pkgName,
-			LicenseSpdxID: lcs,
-		})
-		return nil
+// It's a necessary procedure to check the LICENSE file, because the resolver needs to record the license content
+func (resolver *NpmResolver) ResolvePackageLicense(pkgName, pkgPath string) *Result {
+	result := &Result{
+		Dependency: pkgName,
 	}
-	resolveErrs = err
+	// resolve from the package.json file
+	if err := resolver.ResolvePkgFile(result, pkgPath); err != nil {
+		result.ResolveErrors = append(result.ResolveErrors, err)
+	}
 
-	lcs, err = resolver.ResolveLcsFile(pkgName, pkgPath)
-	if err == nil {
-		report.Resolve(&Result{
-			Dependency:    pkgName,
-			LicenseSpdxID: lcs,
-		})
-		return nil
+	// resolve from the LICENSE file
+	if err := resolver.ResolveLcsFile(result, pkgPath); err != nil {
+		result.ResolveErrors = append(result.ResolveErrors, err)
 	}
-	resolveErrs = fmt.Errorf("%+v; %+v", resolveErrs, err)
-	return resolveErrs
+
+	return result
 }
 
 // ResolvePkgFile tries to find and parse the package.json file to capture the license field
-func (resolver *NpmResolver) ResolvePkgFile(pkgFile string) (string, error) {
-	packageInfo, err := resolver.ParsePkgFile(pkgFile)
+func (resolver *NpmResolver) ResolvePkgFile(result *Result, pkgPath string) error {
+	expectedPkgFile := filepath.Join(pkgPath, PkgFileName)
+	packageInfo, err := resolver.ParsePkgFile(expectedPkgFile)
 	if err != nil {
-		return "", err
+		return err
 	}
 
 	if lcs, ok := resolver.ResolveLicenseField(packageInfo.License); ok {
-		return lcs, nil
+		result.LicenseSpdxID = lcs
+		return nil
 	}
 
 	if lcs, ok := resolver.ResolveLicensesField(packageInfo.Licenses); ok {
-		return lcs, nil
+		result.LicenseSpdxID = lcs
+		return nil
 	}
 
-	return "", fmt.Errorf(`cannot parse the "license"/"licenses" field`)
+	return fmt.Errorf(`cannot parse the "license"/"licenses" field`)
 }
 
 // ResolveLicenseField parses and validates the "license" field in package.json file
@@ -262,27 +258,33 @@
 }
 
 // ResolveLcsFile tries to find the license file to identify the license
-func (resolver *NpmResolver) ResolveLcsFile(pkgName, pkgPath string) (string, error) {
+func (resolver *NpmResolver) ResolveLcsFile(result *Result, pkgPath string) error {
 	depFiles, err := ioutil.ReadDir(pkgPath)
 	if err != nil {
-		return "", err
+		return err
 	}
 	for _, info := range depFiles {
 		if info.IsDir() || !possibleLicenseFileName.MatchString(info.Name()) {
 			continue
 		}
 		licenseFilePath := filepath.Join(pkgPath, info.Name())
+		result.LicenseFilePath = licenseFilePath
 		content, err := ioutil.ReadFile(licenseFilePath)
 		if err != nil {
-			return "", err
+			return err
 		}
-		identifier, err := license.Identify(pkgName, string(content))
+		result.LicenseContent = string(content)
+		if result.LicenseSpdxID != "" {
+			return nil
+		}
+		identifier, err := license.Identify(result.Dependency, string(content))
 		if err != nil {
-			return "", err
+			return err
 		}
-		return identifier, nil
+		result.LicenseSpdxID = identifier
+		return nil
 	}
-	return "", fmt.Errorf("cannot find the license file")
+	return fmt.Errorf("cannot find the license file")
 }
 
 // ParsePkgFile parses the content of the package file
diff --git a/pkg/deps/npm_test.go b/pkg/deps/npm_test.go
index ba11961..c914d32 100644
--- a/pkg/deps/npm_test.go
+++ b/pkg/deps/npm_test.go
@@ -88,9 +88,9 @@
 		t.Fatal(err)
 	}
 	defer os.RemoveAll(dir)
-
 	resolver := new(deps.NpmResolver)
 	for _, data := range TestData {
+		result := &deps.Result{}
 		f, err := ioutil.TempFile(dir, "*.json")
 		if err != nil {
 			t.Fatal(err)
@@ -99,9 +99,8 @@
 		if err != nil {
 			t.Fatal(err)
 		}
-
-		lcs, err := resolver.ResolvePkgFile(f.Name())
-		if lcs != data.result && (err != nil) == data.hasErr {
+		err = resolver.ResolvePkgFile(result, f.Name())
+		if result.LicenseSpdxID != data.result && (err != nil) == data.hasErr {
 			t.Fail()
 		}
 		_ = f.Close()
diff --git a/pkg/deps/result.go b/pkg/deps/result.go
index 6bfc104..f460bcc 100644
--- a/pkg/deps/result.go
+++ b/pkg/deps/result.go
@@ -35,6 +35,7 @@
 	LicenseFilePath string
 	LicenseContent  string
 	LicenseSpdxID   string
+	ResolveErrors   []error
 }
 
 // Report is a collection of resolved Result.