Repository: webscopeio/license.sh

Issue:
[NPM] License priority
Version specific license should have priority

https://registry.npmjs.org/foreachasync

3.0.0 - Apache2
Global - (Apache2 or MIT)

Discussion:

Patch:
diff --git a/license_sh/helpers.py b/license_sh/helpers.py
index b00c499..414d90b 100644
--- a/license_sh/helpers.py
+++ b/license_sh/helpers.py
@@ -67,6 +67,18 @@ def extract_npm_license(json_data, version: str):
     """
     if not json_data:
         return None
+    version_data = json_data.get("versions", {}).get(version, {})
+    licenses_array = version_data.get("licenses")
+    if licenses_array:
+        return get_npm_license_from_licenses_array(licenses_array)
+    license_name = version_data.get("license")
+    if license_name:
+        return (
+            license_name.get("type")
+            if type(license_name) is dict
+            else f"{license_name}"
+        )
+
     licenses_array = json_data.get("licenses")
     if licenses_array:
         return get_npm_license_from_licenses_array(licenses_array)
@@ -79,11 +91,7 @@ def extract_npm_license(json_data, version: str):
             else f"{license_name}"
         )
 
-    version_data = json_data.get("versions", {}).get(version, {})
-    licenses_array = version_data.get("licenses")
-    if licenses_array:
-        return get_npm_license_from_licenses_array(licenses_array)
-    return version_data.get("license", None)
+    return None
 
 
 def flatten_dependency_tree(tree):
@@ -151,9 +159,11 @@ def is_license_ok(license_text, whitelist):
 
 
 def normalize_license_expression(license_text_raw):
-    if license_text_raw is None:
-        return None
-    license_text, normalized = normalize(f"{license_text_raw}")
+    if license_text_raw:
+        data = normalize(f"{license_text_raw}")
+        license_text, normalized = data
+    else:
+        license_text = None
     try:
         license = licensing.parse(license_text)
     except:
diff --git a/license_sh/runners/maven/__init__.py b/license_sh/runners/maven/__init__.py
index 6bdd75a..4ed30e0 100644
--- a/license_sh/runners/maven/__init__.py
+++ b/license_sh/runners/maven/__init__.py
@@ -1,5 +1,4 @@
 import tempfile
-import sys
 from contextlib import nullcontext
 from os import path
 import xml.etree.ElementTree as ET
@@ -68,13 +67,7 @@ def get_dependency_tree_xml(directory: str, debug=False):
             ],
             capture_output=not debug,
         )
-        try:
-            return ET.parse(tmpfile).getroot()
-        except:
-            print(
-                f"Couldn't get data from maven...", file=sys.stderr,
-            )
-            exit(1)
+        return ET.parse(tmpfile).getroot()
 
     return None
 
diff --git a/license_sh/runners/npm/__init__.py b/license_sh/runners/npm/__init__.py
index 8410874..2e1bc40 100644
--- a/license_sh/runners/npm/__init__.py
+++ b/license_sh/runners/npm/__init__.py
@@ -1,5 +1,4 @@
 import json
-import sys
 import subprocess
 from os import path
 from contextlib import nullcontext
@@ -77,11 +76,6 @@ def get_dependency_tree(package_json, package_lock_tree):
 
     # load root dependencies from package.json
     for dep_name in package_json.get("dependencies", {}).keys():
-        if not dep_name in package_lock_tree:
-            print(
-                f"{dep_name} package not found in package-lock.json", file=sys.stderr,
-            )
-            exit(1)
         dependency = package_lock_tree[dep_name]
         version = dependency.get("version")
         parent = AnyNode(
diff --git a/license_sh/runners/yarn/__init__.py b/license_sh/runners/yarn/__init__.py
index 2ed68ac..098b070 100644
--- a/license_sh/runners/yarn/__init__.py
+++ b/license_sh/runners/yarn/__init__.py
@@ -1,6 +1,5 @@
 import json
 import subprocess
-import sys
 from os import path
 from anytree import AnyNode, PreOrderIter
 from typing import Dict, List, Tuple
@@ -278,14 +277,8 @@ def get_dependency_tree(
         resolved_version = package_map.get(
             f"{dep_name}@{dep_version}"
         )  # Resolve locked version of the package
-        full_name = f"{dep_name}@{resolved_version}"
-        if full_name not in flat_tree.keys():
-            print(
-                f"{dep_name} package not found in yarn.lock", file=sys.stderr,
-            )
-            exit(1)
         dependency = flat_tree.get(
-            full_name
+            f"{dep_name}@{resolved_version}"
         )  # Use package full name to get it dependencies
         # Create first level of nodes based on package.json dependencies
         parent = AnyNode(


Test patch:
diff --git a/tests/runners/test_helpers.py b/tests/test_helpers.py
similarity index 99%
rename from tests/runners/test_helpers.py
rename to tests/test_helpers.py
index 1b168d2..56ef798 100644
--- a/tests/runners/test_helpers.py
+++ b/tests/test_helpers.py
@@ -432,7 +432,7 @@ class NpmRunnerTestCase(unittest.TestCase):
         name = extract_npm_license(data, "1.0.0")
         self.assertEqual(name, "APACHE")
 
-    def test_extract_npm_license_global_priority(self):
+    def test_extract_npm_license_version_priority(self):
         data = json.loads(
             """{
             "name": "name",
@@ -445,7 +445,7 @@ class NpmRunnerTestCase(unittest.TestCase):
         }"""
         )
         name = extract_npm_license(data, "1.0.0")
-        self.assertEqual(name, "MIT")
+        self.assertEqual(name, "APACHE")
 
     def test_extract_npm_license_no_versions(self):
         data = json.loads(