Repository: porscheinformatik/sonarqube-licensecheck
Pull request #53 (2019-05-31 10:25:07)

Update dependency org.glassfish:javax.json to v1.1.4
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [org.glassfish:javax.json](https://javaee.github.io/jsonp) | minor | `1.0.2` -> `1.1.4` |

---

### Renovate configuration

:date: **Schedule**: At any time (no schedule defined).

:vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

:recycle: **Rebasing**: Whenever PR becomes conflicted, or if you modify the PR title to begin with "`rebase!`".

:no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- renovate-rebase -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://togithub.com/marketplace/renovate). View repository job log [here](https://renovatebot.com/dashboard#porscheinformatik/sonarqube-licensecheck).


Patch:
diff --git a/.travis.yml b/.travis.yml
index 874b2ed..7d2c574 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ language: java
 jdk:
 - oraclejdk8
 - openjdk11
+if: type != push OR branch = master OR branch =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
 addons:
   sonarcloud:
     organization: "porscheinformatik"
diff --git a/README.md b/README.md
index 4e34b88..abf7c21 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@ SonarQube License-Check
 ===================
 
 [![Build Status](https://travis-ci.org/porscheinformatik/sonarqube-licensecheck.png?branch=master)](https://travis-ci.org/porscheinformatik/sonarqube-licensecheck)
+[![Maintainability](https://api.codeclimate.com/v1/badges/6ac787bb79b43e39c367/maintainability)](https://codeclimate.com/github/porscheinformatik/sonarqube-licensecheck/maintainability)
 
 This [SonarQube](http://www.sonarqube.org/) plugin ensures that projects in an organization adhere to a set of
 standard libraries and versions. This enables the governance of the used libraries and licences.
@@ -13,9 +14,10 @@ This software is licensed under the [Apache Software License, Version 2.0](http:
 ## Compatibility
 
 This plugin is compatible:
- 
+
  * 1.x versions with SonarQube >= 5.3 and < 6.
  * 2.x version with SonarQube >= 6.5 and < 7.
+ * 3.x version with SonarQube >= 6.7 LTS and < 8.
 
 ## Installation
 
@@ -32,8 +34,8 @@ After booting the SonarQube Server with the License-Check Plugin two new options
 <b>Administration</b>.
 
 * Within the general settings the plugin can be manually enabled or disabled. By default it is enabled.
-* All other configuration is under License-Check specific settings (Configuration > License Check). 
-  * Under "Licenses" you can allow or disallow licenses globally and add/edit the list of known licenses. 
+* All other configuration is under License-Check specific settings (Configuration > License Check).
+  * Under "Licenses" you can allow or disallow licenses globally and add/edit the list of known licenses.
   * Under "Project Licenses" you can allow and disallow licenses for a specific project.
   * Under "Maven Dependencies" you can map the Maven key (groupId:artifactId) to licenses using regular expressions. E.g. `^asm:asm$` to "BSD-3-Clause"
   * Under "Maven Licenses" you can map Maven license texts to licenses using regular expressions, e.g. `.*Apache.*2.*` to "Apache-2.0".
@@ -45,15 +47,16 @@ configuration](docs/licensecheck_configuration.jpg)
 
 ### Analysis
 
-The plugin scans for dependencies defined in your project including all transitive dependencies. 
+The plugin scans for dependencies defined in your project including all transitive dependencies.
 
 Currently supported formats are:
 * Maven POM files - all dependencies with scope "compile" and "runtime" are checked
 * NPM package.json files - all dependencies (except "devDependencies") are checked
+  * Note that transitive dependencies are _not_ scanned unless `licensecheck.npm.resolvetransitive` is set to `true`.
 
 ### Project Dashboard
 
-The plugin contains a project dashboard showing a list of dependencies with version and a list of all used licences. Each table shows the status of the license 
+The plugin contains a project dashboard showing a list of dependencies with version and a list of all used licences. Each table shows the status of the license
 (allowed, not allowed, not found). You can also export the data to Excel.
 
 Example for "Dependencies" table:
diff --git a/pom.xml b/pom.xml
index 129d203..8b94a9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
   <groupId>at.porscheinformatik.sonarqube.licensecheck</groupId>
   <artifactId>sonarqube-licensecheck-plugin</artifactId>
-  <version>3.0.0-SNAPSHOT</version>
+  <version>4.0.0-SNAPSHOT</version>
   <name>SonarQube License Check Plugin</name>
   <packaging>sonar-plugin</packaging>
 
@@ -50,7 +50,7 @@
     <dependency>
       <groupId>org.glassfish</groupId>
       <artifactId>javax.json</artifactId>
-      <version>1.0.2</version>
+      <version>1.1.4</version>
     </dependency>
     <dependency>
       <groupId>commons-cli</groupId>
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/Dependency.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/Dependency.java
index ddc50ab..48c35ee 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/Dependency.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/Dependency.java
@@ -5,6 +5,7 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.TreeSet;
 
 import javax.json.Json;
@@ -80,66 +81,26 @@ public class Dependency implements Comparable<Dependency>
     }
 
     @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((license == null) ? 0 : license.hashCode());
-        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
-        result = (prime * result) + ((version == null) ? 0 : version.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj)
+    public boolean equals(Object o)
     {
-        if (this == obj)
+        if (this == o)
         {
             return true;
         }
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        Dependency other = (Dependency) obj;
-        if (license == null)
-        {
-            if (other.license != null)
-            {
-                return false;
-            }
-        }
-        else if (!license.equals(other.license))
-        {
-            return false;
-        }
-        if (name == null)
-        {
-            if (other.name != null)
-            {
-                return false;
-            }
-        }
-        else if (!name.equals(other.name))
+        if (o == null || getClass() != o.getClass())
         {
             return false;
         }
-        if (version == null)
-        {
-            if (other.version != null)
-            {
-                return false;
-            }
-        }
-        else if (!version.equals(other.version))
-        {
-            return false;
-        }
-        return true;
+        Dependency that = (Dependency) o;
+        return Objects.equals(name, that.name) &&
+            Objects.equals(version, that.version) &&
+            Objects.equals(license, that.license);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(name, version, license);
     }
 
     @Override
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckPropertyKeys.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckPropertyKeys.java
index eae2ec8..e77b657 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckPropertyKeys.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckPropertyKeys.java
@@ -9,4 +9,6 @@ public class LicenseCheckPropertyKeys
     public static final String ALLOWED_DEPENDENCIES_KEY = "licensecheck.alloweddependencies";
 
     public static final String PROJECT_LICENSE_KEY = "licensecheck.projectlicense";
+
+    public static final String NPM_RESOLVE_TRANSITVE_DEPS = "licensecheck.npm.resolvetransitive";
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckSensor.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckSensor.java
index 4378ad5..83d37c4 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckSensor.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/LicenseCheckSensor.java
@@ -2,7 +2,6 @@ package at.porscheinformatik.sonarqube.licensecheck;
 
 import static java.util.Collections.newSetFromMap;
 
-import java.util.Collections;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
@@ -44,7 +43,7 @@ public class LicenseCheckSensor implements Sensor
         this.settings = settings;
         this.validateLicenses = validateLicenses;
         this.scanners = new Scanner[]{
-            new PackageJsonDependencyScanner(),
+            new PackageJsonDependencyScanner(settings.getBoolean(LicenseCheckPropertyKeys.NPM_RESOLVE_TRANSITVE_DEPS)),
             new MavenDependencyScanner(mavenLicenseService, mavenDependencyService)};
     }
 
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/ValidateLicenses.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/ValidateLicenses.java
index f2494ff..2850108 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/ValidateLicenses.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/ValidateLicenses.java
@@ -85,15 +85,15 @@ public class ValidateLicenses
             {
                 String notAllowedLicense = "";
 
-                for(License element : licensesContainingDependency) {
-                    if(element.getStatus() == "false") {
+                for (License element : licensesContainingDependency) {
+                    if (element.getStatus() == "false") {
                         notAllowedLicense += element.getName() + " ";
                     }
                 }
                 licenseNotAllowedIssue(context, dependency, notAllowedLicense);
             }
         }
-    }    
+    }
 
     private boolean checkSpdxLicense(String spdxLicenseString, List<License> licenses)
     {
@@ -115,7 +115,7 @@ public class ValidateLicenses
             .isPresent();
     }
 
-    private boolean checkSpdxLicenseWithOr(String spdxLicenseString, List<License> licenses){
+    private boolean checkSpdxLicenseWithOr(String spdxLicenseString, List<License> licenses) {
         String[] orLicenses = spdxLicenseString.replace("(", "").replace(")", "").split(" OR ");
         return licenses
             .stream()
@@ -138,7 +138,7 @@ public class ValidateLicenses
         {
             return true;
         }
-        else if(foundLicenses.size() == count)
+        else if (foundLicenses.size() == count)
         {
             // NOT ALLOWED
             return false;
@@ -177,7 +177,7 @@ public class ValidateLicenses
         issue.save();
     }
 
-    private static boolean contains(String[] items, String valueToFind) 
+    private static boolean contains(String[] items, String valueToFind)
     {
         for (String item : items)
         {
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/interfaces/Scanner.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/interfaces/Scanner.java
index 9fdddfe..f3af084 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/interfaces/Scanner.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/interfaces/Scanner.java
@@ -1,11 +1,11 @@
 package at.porscheinformatik.sonarqube.licensecheck.interfaces;
 
 import java.io.File;
-import java.util.List;
+import java.util.Set;
 
 import at.porscheinformatik.sonarqube.licensecheck.Dependency;
 
 public interface Scanner
 {
-    List<Dependency> scan(File moduleDir);
+    Set<Dependency> scan(File moduleDir);
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/License.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/License.java
index 9da7132..22dc06a 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/License.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/License.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.TreeSet;
 
 import javax.json.Json;
@@ -61,17 +62,6 @@ public class License implements Comparable<License>
         this.status = status;
     }
 
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((identifier == null) ? 0 : identifier.hashCode());
-        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
-        result = (prime * result) + ((status == null) ? 0 : status.hashCode());
-        return result;
-    }
-
     @Override
     public String toString()
     {
@@ -80,38 +70,46 @@ public class License implements Comparable<License>
 
     public static List<License> fromString(String serializedLicensesString)
     {
-        List<License> licenses = new ArrayList<>();
+        if (serializedLicensesString == null)
+        {
+            return new ArrayList<>();
+        }
 
-        if (serializedLicensesString != null)
+        if (serializedLicensesString.startsWith("["))
         {
-            if (serializedLicensesString.startsWith("["))
+            List<License> licenses = new ArrayList<>();
+
+            try (JsonReader jsonReader = Json.createReader(new StringReader(serializedLicensesString)))
             {
-                try (JsonReader jsonReader = Json.createReader(new StringReader(serializedLicensesString)))
+                JsonArray licensesJson = jsonReader.readArray();
+                for (JsonObject licenseJson : licensesJson.getValuesAs(JsonObject.class))
                 {
-                    JsonArray licensesJson = jsonReader.readArray();
-                    for (JsonObject licenseJson : licensesJson.getValuesAs(JsonObject.class))
-                    {
-                        licenses.add(new License(licenseJson.getString("name"), licenseJson.getString("identifier"),
-                            licenseJson.getString("status")));
-                    }
+                    licenses.add(new License(licenseJson.getString("name"), licenseJson.getString("identifier"),
+                        licenseJson.getString("status")));
                 }
             }
-            else if (serializedLicensesString.startsWith("{"))
-            {
-                readLegacyJson(serializedLicensesString, licenses);
-            }
-            else
-            {
-                readLegaySeparated(serializedLicensesString, licenses);
-            }
+            return licenses;
+        }
+        else if (serializedLicensesString.startsWith("{"))
+        {
+            return readLegacyJson(serializedLicensesString);
+        }
+        else
+        {
+            return readLegacySeparated(serializedLicensesString);
         }
-        return licenses;
     }
 
+    /**
+     * @deprecated remove with later release
+     * @param serializedLicensesString setting string
+     * @return a list with licences
+     */
     @Deprecated
-    private static void readLegaySeparated(String serializedLicensesString, List<License> licenses)
+    private static List<License> readLegacySeparated(String serializedLicensesString)
     {
-        // deprecated - remove with later release
+        List<License> licenses = new ArrayList<>();
+
         if (StringUtils.isNotEmpty(serializedLicensesString))
         {
             String[] parts = serializedLicensesString.split(";");
@@ -125,12 +123,20 @@ public class License implements Comparable<License>
                 licenses.add(new License(name, identifier, status));
             }
         }
+
+        return licenses;
     }
 
+    /**
+     * @deprecated remove with later release
+     * @param serializedLicensesString setting string
+     * @return a list with licences
+     */
     @Deprecated
-    private static void readLegacyJson(String serializedLicensesString, List<License> licenses)
+    private static List<License> readLegacyJson(String serializedLicensesString)
     {
-        // deprecated - remove with later release
+        List<License> licenses = new ArrayList<>();
+
         try (JsonReader jsonReader = Json.createReader(new StringReader(serializedLicensesString)))
         {
             JsonObject licensesJson = jsonReader.readObject();
@@ -141,6 +147,8 @@ public class License implements Comparable<License>
                     value.getString("status")));
             }
         }
+
+        return licenses;
     }
 
     public static String createString(Collection<License> licenses)
@@ -172,7 +180,8 @@ public class License implements Comparable<License>
         {
             return 1;
         }
-        else if (this.identifier.compareTo(o.identifier) == 0)
+
+        if (this.identifier.compareTo(o.identifier) == 0)
         {
             if (this.name.compareTo(o.name) == 0)
             {
@@ -190,22 +199,25 @@ public class License implements Comparable<License>
     }
 
     @Override
-    public boolean equals(Object object)
+    public boolean equals(Object o)
     {
-        if (this == object)
+        if (this == o)
         {
             return true;
         }
-        if (object == null)
-        {
-            return false;
-        }
-        if (getClass() != object.getClass())
+        if (o == null || getClass() != o.getClass())
         {
             return false;
         }
+        License license = (License) o;
+        return Objects.equals(name, license.name) &&
+            Objects.equals(identifier, license.identifier) &&
+            Objects.equals(status, license.status);
+    }
 
-        License license = (License) object;
-        return license.identifier.equals(this.identifier) && license.name.equals(this.name);
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(name, identifier, status);
     }
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/LicenseSettingsService.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/LicenseSettingsService.java
index bed5b10..3fdbcd9 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/LicenseSettingsService.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/license/LicenseSettingsService.java
@@ -2,9 +2,7 @@ package at.porscheinformatik.sonarqube.licensecheck.license;
 
 import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckPropertyKeys.LICENSE_KEY;
 
-import java.io.BufferedReader;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -15,6 +13,8 @@ import org.sonar.api.config.Settings;
 import org.sonar.api.server.ServerSide;
 import org.sonar.server.platform.PersistentSettings;
 
+import at.porscheinformatik.sonarqube.licensecheck.utils.IOUtils;
+
 @ServerSide
 public class LicenseSettingsService
 {
@@ -137,29 +137,16 @@ public class LicenseSettingsService
     {
         String licenseJson = settings.getString(LICENSE_KEY);
 
-        if ((licenseJson != null) && !licenseJson.isEmpty())
+        if (licenseJson != null && !licenseJson.isEmpty())
         {
             return;
         }
 
-        try
+        try(InputStream inputStream = LicenseSettingsService.class.getResourceAsStream("spdx_license_list.json");)
         {
-            InputStream inputStream = LicenseService.class.getResourceAsStream("spdx_license_list.json");
-            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
-            StringBuilder out = new StringBuilder();
-            String line;
-
-            while ((line = reader.readLine()) != null)
-            {
-                out.append(line);
-            }
-
-            String newJsonLicense = out.toString();
-            settings.setProperty(LICENSE_KEY, newJsonLicense);
-            persistentSettings.saveProperty(LICENSE_KEY, newJsonLicense);
-
-            reader.close();
-            inputStream.close();
+            String spdxLicenseListJson = IOUtils.readToString(inputStream);
+            settings.setProperty(LICENSE_KEY, spdxLicenseListJson);
+            persistentSettings.saveProperty(LICENSE_KEY, spdxLicenseListJson);
         }
         catch (Exception e)
         {
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScanner.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScanner.java
index 9a7075d..5236fdc 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScanner.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScanner.java
@@ -10,6 +10,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -55,8 +56,16 @@ public class MavenDependencyScanner implements Scanner
     }
 
     @Override
-    public List<Dependency> scan(File moduleDir)
+    public Set<Dependency> scan(File moduleDir)
     {
+        if (!new File(moduleDir, "pom.xml").exists())
+        {
+            LOGGER.info("No pom.xml file found in {} - skipping Maven dependency scan", moduleDir.getPath());
+            return Collections.emptySet();
+        }
+
+        LOGGER.info("Scanning for Maven dependencies");
+
         String userSettings = null;
         String globalSettings = null;
         CommandLine cmd = getCommandLineArgs();
@@ -72,13 +81,13 @@ public class MavenDependencyScanner implements Scanner
             }
         }
 
-        return this.readDependecyList(moduleDir, userSettings, globalSettings)
+        return this.readDependencyList(moduleDir, userSettings, globalSettings)
             .map(this.loadLicenseFromPom(mavenLicenseService.getLicenseMap(), userSettings, globalSettings))
             .map(this::mapMavenDependencyToLicense)
-            .collect(Collectors.toList());
+            .collect(Collectors.toSet());
     }
 
-    private Stream<Dependency> readDependecyList(File moduleDir, String userSettings, String globalSettings)
+    private Stream<Dependency> readDependencyList(File moduleDir, String userSettings, String globalSettings)
     {
         Path tempFile = createTempFile();
         if (tempFile == null)
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavendependency/MavenDependency.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavendependency/MavenDependency.java
index 6b02526..12b428b 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavendependency/MavenDependency.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavendependency/MavenDependency.java
@@ -1,5 +1,7 @@
 package at.porscheinformatik.sonarqube.licensecheck.mavendependency;
 
+import java.util.Objects;
+
 public class MavenDependency implements Comparable<MavenDependency>
 {
     private String key;
@@ -12,16 +14,6 @@ public class MavenDependency implements Comparable<MavenDependency>
         this.license = license;
     }
 
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((key == null) ? 0 : key.hashCode());
-        result = (prime * result) + ((license == null) ? 0 : license.hashCode());
-        return result;
-    }
-
     public String getKey()
     {
         return key;
@@ -55,7 +47,8 @@ public class MavenDependency implements Comparable<MavenDependency>
         {
             return 1;
         }
-        else if (this.license.compareTo(o.license) == 0)
+
+        if (this.license.compareTo(o.license) == 0)
         {
             return this.key.compareTo(o.key);
         }
@@ -66,22 +59,24 @@ public class MavenDependency implements Comparable<MavenDependency>
     }
 
     @Override
-    public boolean equals(Object object)
+    public boolean equals(Object o)
     {
-        if (this == object)
+        if (this == o)
         {
             return true;
         }
-        if (object == null)
-        {
-            return false;
-        }
-        if (getClass() != object.getClass())
+        if (o == null || getClass() != o.getClass())
         {
             return false;
         }
+        MavenDependency that = (MavenDependency) o;
+        return Objects.equals(key, that.key) &&
+            Objects.equals(license, that.license);
+    }
 
-        MavenDependency mavenDependency = (MavenDependency) object;
-        return mavenDependency.license.equals(this.license) && mavenDependency.key.equals(this.key);
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(key, license);
     }
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicense.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicense.java
index 6506f70..39f0d2a 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicense.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicense.java
@@ -5,6 +5,7 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
 
@@ -55,37 +56,6 @@ public class MavenLicense implements Comparable<MavenLicense>
         }
     }
 
-    @Override
-    public boolean equals(Object object)
-    {
-        if (this == object)
-        {
-            return true;
-        }
-        if (object == null)
-        {
-            return false;
-        }
-        if (getClass() != object.getClass())
-        {
-            return false;
-        }
-
-        MavenLicense mavenLicense = (MavenLicense) object;
-        return mavenLicense.license.equals(this.license)
-            && mavenLicense.regex.toString().equals(this.regex.toString());
-    }
-
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((license == null) ? 0 : license.hashCode());
-        result = (prime * result) + ((regex == null) ? 0 : regex.hashCode());
-        return result;
-    }
-
     public static List<MavenLicense> fromString(String mavenLicenseString)
     {
         List<MavenLicense> mavenLicenses = new ArrayList<>();
@@ -99,7 +69,7 @@ public class MavenLicense implements Comparable<MavenLicense>
                 {
                     JsonObject licenseJson = licensesJson.getJsonObject(i);
                     String regex = null;
-                    try 
+                    try
                     {
                         regex = licenseJson.getString("regex");
                     }
@@ -149,4 +119,26 @@ public class MavenLicense implements Comparable<MavenLicense>
 
         return jsonString.toString();
     }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass())
+        {
+            return false;
+        }
+        MavenLicense that = (MavenLicense) o;
+        return Objects.equals(regex, that.regex) &&
+            Objects.equals(license, that.license);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(regex, license);
+    }
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicenseSettingsService.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicenseSettingsService.java
index add1486..0f6b125 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicenseSettingsService.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/MavenLicenseSettingsService.java
@@ -2,17 +2,24 @@ package at.porscheinformatik.sonarqube.licensecheck.mavenlicense;
 
 import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckPropertyKeys.LICENSE_REGEX;
 
+import java.io.InputStream;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.sonar.api.config.Settings;
 import org.sonar.api.server.ServerSide;
 import org.sonar.server.platform.PersistentSettings;
 
+import at.porscheinformatik.sonarqube.licensecheck.utils.IOUtils;
+
 @ServerSide
 public class MavenLicenseSettingsService
 {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MavenLicenseSettingsService.class);
+
     /** This is not official API */
     private final PersistentSettings persistentSettings;
     private final Settings settings;
@@ -25,6 +32,28 @@ public class MavenLicenseSettingsService
         this.persistentSettings = persistentSettings;
         this.settings = settings;
         this.mavenLicenseService = mavenLicenseService;
+        initMavenLicenses();
+    }
+
+    private void initMavenLicenses()
+    {
+        String mavenLicenseListString = settings.getString(LICENSE_REGEX);
+
+        if (mavenLicenseListString != null && !mavenLicenseListString.isEmpty())
+        {
+            return;
+        }
+
+        try(InputStream in = MavenLicenseSettingsService.class.getResourceAsStream("default_license_mapping.json"))
+        {
+            mavenLicenseListString = IOUtils.readToString(in);
+            settings.setProperty(LICENSE_REGEX, mavenLicenseListString);
+            persistentSettings.saveProperty(LICENSE_REGEX, mavenLicenseListString);
+        }
+        catch(Exception e)
+        {
+            LOGGER.error("Could not load default_license_mapping.json", e);
+        }
     }
 
     public boolean addMavenLicense(String regex, String key)
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/npm/PackageJsonDependencyScanner.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/npm/PackageJsonDependencyScanner.java
index bb2e3de..785fc01 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/npm/PackageJsonDependencyScanner.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/npm/PackageJsonDependencyScanner.java
@@ -5,9 +5,9 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.json.Json;
 import javax.json.JsonArray;
@@ -24,89 +24,111 @@ public class PackageJsonDependencyScanner implements Scanner
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(PackageJsonDependencyScanner.class);
 
+    private boolean resolveTransitiveDeps;
+
+    public PackageJsonDependencyScanner(boolean resolveTransitiveDeps)
+    {
+        this.resolveTransitiveDeps = resolveTransitiveDeps;
+    }
+
     @Override
-    public List<Dependency> scan(File file)
+    public Set<Dependency> scan(File moduleDir)
     {
-        File packageJsonFile = new File(file, "package.json");
+        File packageJsonFile = new File(moduleDir, "package.json");
 
-        if (packageJsonFile.exists())
+        if (!packageJsonFile.exists())
         {
-            try (InputStream fis = new FileInputStream(packageJsonFile);
-                JsonReader jsonReader = Json.createReader(fis))
-            {
-                JsonObject jsonObject = jsonReader.readObject();
-                JsonObject jsonObjectDependencies = jsonObject.getJsonObject("dependencies");
-                if (jsonObjectDependencies != null)
-                {
-                    return dependencyParser(jsonObjectDependencies, packageJsonFile);
-                }
-                jsonReader.close();
-            }
-            catch (IOException e)
-            {
-                LOGGER.error("Error reading package.json", e);
-            }
+            LOGGER.info("No package.json file found in {} - skipping NPM dependency scan", moduleDir.getPath());
+            return Collections.emptySet();
         }
-        return Collections.emptyList();
+
+        LOGGER.info("Scanning for NPM dependencies");
+
+        return dependencyParser(moduleDir, packageJsonFile);
     }
 
-    private List<Dependency> dependencyParser(JsonObject jsonDependencies, File packageJsonFile)
+    private Set<Dependency> dependencyParser(File baseDir, File packageJsonFile)
     {
-        List<Dependency> dependencies = new ArrayList<>();
+        Set<Dependency> dependencies = new HashSet<>();
 
-        File nodeModulesFolder = new File(packageJsonFile.getParentFile(), "node_modules");
-        if (nodeModulesFolder.exists() && nodeModulesFolder.isDirectory())
+        try (InputStream fis = new FileInputStream(packageJsonFile);
+            JsonReader jsonReader = Json.createReader(fis))
         {
-            for (String key : jsonDependencies.keySet())
+            JsonObject packageJson = jsonReader.readObject();
+
+            JsonObject packageJsonDependencies = packageJson.getJsonObject("dependencies");
+            if (packageJsonDependencies != null)
             {
-                moduleCheck(nodeModulesFolder, key, dependencies);
+                scanDependencies(baseDir, packageJsonDependencies.keySet(), dependencies);
             }
         }
+        catch (IOException e)
+        {
+            LOGGER.error("Error reading package.json", e);
+        }
 
         return dependencies;
     }
 
-    private static void moduleCheck(File nodeModulesFolder, String identifier, List<Dependency> dependencies)
+    private void scanDependencies(File baseDir, Set<String> packageNames, Set<Dependency> dependencies)
     {
-        File moduleFolder = new File(nodeModulesFolder, identifier);
+        LOGGER.info("Scanning NPM packages " + packageNames);
 
-        if (moduleFolder.exists() && moduleFolder.isDirectory())
+        for (String packageName : packageNames)
         {
-            File packageFile = new File(moduleFolder, "package.json");
+            if (dependencies.stream().anyMatch(d -> packageName.equals(d.getName())))
+            {
+                LOGGER.debug("Package {} has already been encountered and will not be scanned again", packageName);
+                continue;
+            }
 
-            try (InputStream fis = new FileInputStream(packageFile); JsonReader jsonReader = Json.createReader(fis))
+            File packageJsonFile = new File(baseDir, "node_modules/" + packageName + "/package.json");
+            if (!packageJsonFile.exists())
             {
-                JsonObject jsonObject = jsonReader.readObject();
-                if (jsonObject != null)
+                LOGGER.warn("No package.json file found for package {} in node_modules - skipping dependency",
+                        packageName);
+                continue;
+            }
+
+            try (InputStream fis = new FileInputStream(packageJsonFile);
+                JsonReader jsonReader = Json.createReader(fis))
+            {
+                JsonObject packageJson = jsonReader.readObject();
+                if (packageJson != null)
                 {
-                    String license = null;
-                    if (jsonObject.containsKey("license"))
+                    String license = "";
+                    if (packageJson.containsKey("license"))
                     {
-                        license = jsonObject.getString("license");
+                        license = packageJson.getString("license");
                     }
-                    else if (jsonObject.containsKey("licenses"))
+                    else if (packageJson.containsKey("licenses"))
                     {
-                        JsonArray licenses = jsonObject.getJsonArray("licenses");
+                        JsonArray licenses = packageJson.getJsonArray("licenses");
                         if (licenses.size() > 0)
                         {
                             license = licenses.getJsonObject(0).getString("type");
                         }
                     }
 
-                    if (license != null)
+                    dependencies.add(new Dependency(packageName, packageJson.getString("version"), license));
+
+                    if (resolveTransitiveDeps)
                     {
-                        dependencies.add(new Dependency(identifier, jsonObject.getString("version"), license));
+                        JsonObject packageJsonDependencies = packageJson.getJsonObject("dependencies");
+                        if (packageJsonDependencies != null)
+                        {
+                            scanDependencies(baseDir, packageJsonDependencies.keySet(), dependencies);
+                        }
                     }
                 }
-                jsonReader.close();
             }
             catch (FileNotFoundException e)
             {
-                LOGGER.error("Could not find package.json", e);
+                LOGGER.error("Could not load package.json", e);
             }
             catch (Exception e)
             {
-                LOGGER.error("Error adding dependency " + identifier, e);
+                LOGGER.error("Could not check NPM package " + packageName, e);
             }
         }
     }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/projectLicense/ProjectLicense.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/projectLicense/ProjectLicense.java
index 3708583..296aeed 100644
--- a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/projectLicense/ProjectLicense.java
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/projectLicense/ProjectLicense.java
@@ -5,6 +5,7 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.TreeSet;
 
 import javax.json.Json;
@@ -90,7 +91,8 @@ public class ProjectLicense implements Comparable<ProjectLicense>
         {
             return 1;
         }
-        else if (this.getProjectKey().compareTo(o.getProjectKey()) == 0)
+
+        if (this.getProjectKey().compareTo(o.getProjectKey()) == 0)
         {
             if (this.getLicense().compareTo(o.getLicense()) == 0)
             {
@@ -108,35 +110,25 @@ public class ProjectLicense implements Comparable<ProjectLicense>
     }
 
     @Override
-    public boolean equals(Object object)
+    public boolean equals(Object o)
     {
-        if (this == object)
+        if (this == o)
         {
             return true;
         }
-        if (object == null)
-        {
-            return false;
-        }
-        if (getClass() != object.getClass())
+        if (o == null || getClass() != o.getClass())
         {
             return false;
         }
-
-        ProjectLicense projectLicense = (ProjectLicense) object;
-
-        return projectLicense.getLicense().equals(this.getLicense())
-            && projectLicense.getProjectKey().equals(this.getProjectKey());
+        ProjectLicense that = (ProjectLicense) o;
+        return Objects.equals(projectKey, that.projectKey) &&
+            Objects.equals(license, that.license) &&
+            Objects.equals(status, that.status);
     }
 
     @Override
     public int hashCode()
     {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((getLicense() == null) ? 0 : getLicense().hashCode());
-        result = (prime * result) + ((getProjectKey() == null) ? 0 : getProjectKey().hashCode());
-        result = (prime * result) + ((getStatus() == null) ? 0 : getStatus().hashCode());
-        return result;
+        return Objects.hash(projectKey, license, status);
     }
 }
diff --git a/src/main/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtils.java b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtils.java
new file mode 100644
index 0000000..467e543
--- /dev/null
+++ b/src/main/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtils.java
@@ -0,0 +1,28 @@
+package at.porscheinformatik.sonarqube.licensecheck.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+public class IOUtils
+{
+    private IOUtils()
+    {
+    }
+
+    public static String readToString(InputStream input) throws IOException 
+    {
+        Reader in = new InputStreamReader(input, StandardCharsets.UTF_8);
+        StringWriter out = new StringWriter();
+        int n = 0;
+        char[] buffer = new char[4096];
+        while ((n = in.read(buffer)) != -1)
+        {
+            out.write(buffer, 0, n);
+        }
+        return out.toString();
+    }
+}
diff --git a/src/main/resources/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/default_license_mapping.json b/src/main/resources/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/default_license_mapping.json
new file mode 100644
index 0000000..621b5d6
--- /dev/null
+++ b/src/main/resources/at/porscheinformatik/sonarqube/licensecheck/mavenlicense/default_license_mapping.json
@@ -0,0 +1,31 @@
+[
+  { "regex": "Apple License", "license": "AML" },
+  { "regex": ".*Apache.*1\\.1.*", "license": "Apache-1.1" },
+  { "regex": ".*AL.*2.*", "license": "Apache-2.0" },
+  { "regex": ".*ASF.*2.*", "license": "Apache-2.0" },
+  { "regex": ".*ASL.*", "license": "Apache-2.0" },
+  { "regex": ".*Apache.*2.*", "license": "Apache-2.0" },
+  { "regex": ".*BSD.*", "license": "BSD-3-Clause" },
+  { "regex": "^CC0.*$", "license": "CC0-1.0" },
+  { "regex": ".*CDDL.*", "license": "CDDL-1.0" },
+  { "regex": ".*CDDL.*GPL.*", "license": "(CDDL-1.0 OR GPL-2.0)" },
+  { "regex": ".*CDDL.*1.1.*", "license": "CDDL-1.1" },
+  {
+    "regex": ".*Common Development and Distribution License.*",
+    "license": "CDDL-1.1"
+  },
+  { "regex": ".*Common Public License.*", "license": "CPL-1.0" },
+  { "regex": ".*(EPL|Eclipse Public License).*", "license": "EPL-1.0" },
+  { "regex": ".*LGPL.*2\\.1.*", "license": "LGPL-2.1" },
+  { "regex": ".*Lesser.*Public License.*2\\.1.*", "license": "LGPL-2.1" },
+  { "regex": ".*LGPL.*", "license": "LGPL-3.0" },
+  { "regex": ".*Lesser Public License.*", "license": "LGPL-3.0" },
+  { "regex": ".*MIT.*", "license": "MIT" },
+  { "regex": ".*MPL.*1\\.1.*", "license": "MPL-1.1" },
+  { "regex": ".*Mozilla Public License.*", "license": "MPL-1.1" },
+  { "regex": ".*PostgreSQL License.*", "license": "PostgreSQL" },
+  { "regex": ".*Eclipse.Distribution.License.*.1.0.*", "license": "BSD-3-Clause" },
+  { "regex": ".*GPL2.*CPE.*", "license": "GPL-2.0-with-classpath-exception" },
+  { "regex": ".*JSON.*License.*", "license": "JSON" },
+  { "regex": ".*W3C.Software.*License.*", "license": "W3C"}
+]


Test patch:
diff --git a/src/test/java/at/porscheinformatik/sonarqube/licensecheck/PackageJsonDependencyScannerTest.java b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/PackageJsonDependencyScannerTest.java
index c01c268..99f929d 100644
--- a/src/test/java/at/porscheinformatik/sonarqube/licensecheck/PackageJsonDependencyScannerTest.java
+++ b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/PackageJsonDependencyScannerTest.java
@@ -1,26 +1,66 @@
 package at.porscheinformatik.sonarqube.licensecheck;
 
 import java.io.File;
-import java.util.List;
+import java.util.Set;
 
-import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
 import org.junit.Test;
 
 import at.porscheinformatik.sonarqube.licensecheck.interfaces.Scanner;
 import at.porscheinformatik.sonarqube.licensecheck.npm.PackageJsonDependencyScanner;
 
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertThat;
+
 public class PackageJsonDependencyScannerTest
 {
-    final File folder = new File("src/test/resources");
+    private final File folder = new File("src/test/resources");
 
     @Test
     public void testHappyPath()
     {
-        Scanner scanner = new PackageJsonDependencyScanner();
+        Scanner scanner = new PackageJsonDependencyScanner(false);
+
+        Set<Dependency> dependencies = scanner.scan(folder);
+
+        assertThat(dependencies, hasSize(2));
+        assertThat(dependencies, containsInAnyOrder(
+            new Dependency("angular", "1.5.0", "MIT"),
+            new Dependency("arangojs", "5.6.0", "Apache-2.0")));
+    }
+
+    @Test
+    public void testTransitive()
+    {
+        Scanner scanner = new PackageJsonDependencyScanner(true);
+
+        Set<Dependency> dependencies = scanner.scan(folder);
+
+        assertThat(dependencies, hasSize(4));
+        assertThat(dependencies, containsInAnyOrder(
+            new Dependency("angular", "1.5.0", "MIT"),
+            new Dependency("arangojs", "5.6.0", "Apache-2.0"),
+            new Dependency("linkedlist", "1.0.1", "LGPLv3"),
+            new Dependency("retry", "0.10.1", "MIT")));
+    }
+
+    @Test
+    public void testNoPackageJson()
+    {
+        Scanner scanner = new PackageJsonDependencyScanner(false);
+
+        Set<Dependency> dependencies = scanner.scan(new File("src"));
+
+        assertThat(dependencies, hasSize(0));
+    }
+
+    @Test
+    public void testNoNodeModules()
+    {
+        Scanner scanner = new PackageJsonDependencyScanner(false);
 
-        List<Dependency> dependencies = scanner.scan(folder);
+        Set<Dependency> dependencies = scanner.scan(new File(folder, "node_modules/arangojs"));
 
-        Assert.assertThat(dependencies, CoreMatchers.hasItem(new Dependency("angular", "1.5.0", "MIT")));
+        assertThat(dependencies, hasSize(0));
     }
 }
diff --git a/src/test/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScannerTest.java b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScannerTest.java
index cb89015..6894084 100644
--- a/src/test/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScannerTest.java
+++ b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/maven/MavenDependencyScannerTest.java
@@ -9,8 +9,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.hamcrest.Matchers;
@@ -39,7 +39,7 @@ public class MavenDependencyScannerTest
         Scanner scanner = new MavenDependencyScanner(licenseService, dependencyService);
 
         // -
-        List<Dependency> dependencies = scanner.scan(moduleDir);
+        Set<Dependency> dependencies = scanner.scan(moduleDir);
 
         assertThat(dependencies.size(), Matchers.greaterThan(0));
 
@@ -66,7 +66,7 @@ public class MavenDependencyScannerTest
 
         File moduleDir = Files.createTempDirectory("lala").toFile();
         moduleDir.deleteOnExit();
-        List<Dependency> dependencies = scanner.scan(moduleDir);
+        Set<Dependency> dependencies = scanner.scan(moduleDir);
 
         assertThat(dependencies.size(), is(0));
     }
diff --git a/src/test/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtilsTest.java b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtilsTest.java
new file mode 100644
index 0000000..6b6b3bd
--- /dev/null
+++ b/src/test/java/at/porscheinformatik/sonarqube/licensecheck/utils/IOUtilsTest.java
@@ -0,0 +1,18 @@
+package at.porscheinformatik.sonarqube.licensecheck.utils;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+public class IOUtilsTest
+{
+    @Test
+    public void testLoadFile() throws IOException
+    {
+        String packageJson = IOUtils.readToString(IOUtilsTest.class.getResourceAsStream("/package.json"));
+        assertThat(packageJson, containsString("\"name\": \"test\""));
+    }
+}
diff --git a/src/test/resources/node_modules/arangojs/package.json b/src/test/resources/node_modules/arangojs/package.json
new file mode 100644
index 0000000..0a4db0d
--- /dev/null
+++ b/src/test/resources/node_modules/arangojs/package.json
@@ -0,0 +1,88 @@
+{
+  "name": "arangojs",
+  "version": "5.6.0",
+  "license": "Apache-2.0",
+  "description": "The official ArangoDB JavaScript driver.",
+  "homepage": "https://github.com/arangodb/arangojs",
+  "author": "ArangoDB GmbH",
+  "keywords": [
+    "arango",
+    "arangodb",
+    "aql",
+    "nosql",
+    "client",
+    "driver",
+    "api",
+    "http",
+    "rest"
+  ],
+  "main": "lib/index.js",
+  "browser": {
+    "./lib/util/btoa.js": "./lib/util/btoa.web.js",
+    "./lib/util/bytelength.js": "./lib/util/bytelength.web.js",
+    "./lib/util/multipart.js": "./lib/util/multipart.web.js",
+    "./lib/util/request.js": "./lib/util/request.web.js"
+  },
+  "directories": {
+    "lib": "lib"
+  },
+  "files": [
+    "lib/",
+    "package.json",
+    "arangojs.d.ts",
+    "README.md",
+    "LICENSE"
+  ],
+  "typings": "arangojs.d.ts",
+  "scripts": {
+    "test": "mocha --growl",
+    "lint": "snazzy --verbose src/**/*.js test/**/*.js",
+    "ci": "mocha",
+    "watch": "npm-run-all -p watch:*",
+    "watch:browser": "npm run dist:browser -- --watch",
+    "watch:node": "watch 'npm run dist:node' ./src ./test",
+    "watch:test": "watch 'npm run lint && npm run test' ./src ./test",
+    "dist": "npm-run-all -p dist:*",
+    "dist:browser": "webpack",
+    "dist:node": "babel --compact false -d lib src",
+    "prepublish": "npm run lint && npm run dist && node -e 'require(\"./\");'"
+  },
+  "dependencies": {
+    "linkedlist": "^1.0.1",
+    "retry": "^0.10.0"
+  },
+  "devDependencies": {
+    "babel-cli": "6.22.2",
+    "babel-core": "6.22.1",
+    "babel-loader": "6.2.9",
+    "babel-plugin-add-module-exports": "0.2.1",
+    "babel-plugin-transform-builtin-extend": "1.1.0",
+    "babel-plugin-transform-es2015-modules-commonjs": "6.22.0",
+    "babel-preset-es2015": "6.22.0",
+    "babel-preset-stage-1": "6.22.0",
+    "chai": "3.5.0",
+    "core-js": "2.4.1",
+    "coveralls": "2.11.15",
+    "istanbul": "0.4.5",
+    "json-loader": "0.5.4",
+    "mocha": "3.2.0",
+    "npm-run-all": "4.0.1",
+    "snazzy": "6.0.0",
+    "standard": "8.6.0",
+    "watch": "1.0.1",
+    "webpack": "1.14.0"
+  },
+  "contributors": [
+    {
+      "name": "Alan Plum",
+      "email": "me@pluma.io"
+    }
+  ],
+  "bugs": {
+    "url": "https://github.com/arangodb/arangojs/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/arangodb/arangojs.git"
+  }
+}
diff --git a/src/test/resources/node_modules/linkedlist/package.json b/src/test/resources/node_modules/linkedlist/package.json
new file mode 100644
index 0000000..fed11ff
--- /dev/null
+++ b/src/test/resources/node_modules/linkedlist/package.json
@@ -0,0 +1,28 @@
+{
+  "author": "Kilian Ciuffolo <me@nailik.org> (http://nailik.org)",
+  "name": "linkedlist",
+  "licenses": [{
+    "type": "LGPLv3"
+  }],
+  "description": "Array like linked list with iterator",
+  "keywords": ["array", "linked", "list", "linkedlist", "iterator"],
+  "version": "1.0.1",
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/kilianc/node-linkedlist.git"
+  },
+  "main" : "./",
+  "scripts": {
+    "test": "make test"
+  },
+  "engines": {
+    "node": ">= v0.6.x"
+  },
+  "dependencies": {
+    "retry": "^1.2.3"
+  },
+  "devDependencies": {
+    "mocha": "1.0.x",
+    "should": "0.6.1"
+  }
+}
diff --git a/src/test/resources/node_modules/retry/package.json b/src/test/resources/node_modules/retry/package.json
new file mode 100644
index 0000000..77a7d12
--- /dev/null
+++ b/src/test/resources/node_modules/retry/package.json
@@ -0,0 +1,26 @@
+{
+  "author": "Tim Koschützki <tim@debuggable.com> (http://debuggable.com/)",
+  "name": "retry",
+  "description": "Abstraction for exponential and custom retry strategies for failed operations.",
+  "license": "MIT",
+  "version": "0.10.1",
+  "homepage": "https://github.com/tim-kos/node-retry",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/tim-kos/node-retry.git"
+  },
+  "directories": {
+    "lib": "./lib"
+  },
+  "main": "index",
+  "engines": {
+    "node": "*"
+  },
+  "dependencies": {
+    "linkedlist": "^1.0.1"
+  },
+  "devDependencies": {
+    "fake": "0.2.0",
+    "far": "0.0.1"
+  }
+}
diff --git a/src/test/resources/package.json b/src/test/resources/package.json
index 909f0c9..af1d969 100644
--- a/src/test/resources/package.json
+++ b/src/test/resources/package.json
@@ -6,10 +6,11 @@
   "dependencies": {
     "angular": "^1.4.3",
     "angular-ui-router" : "~0.2.18",
-    "angular-ui-bootstrap" : "1.1.2"
+    "angular-ui-bootstrap" : "1.1.2",
+    "arangojs" : "5.6.0"
   },
   "devDependencies": {
     "gulp": "^3.9.1"
   },
   "license": "MIT"
-}
\ No newline at end of file
+}