Repository: CycloneDX/cdxgen (js)

Issue:
[Gradle] cdxgen doesn't support 'jetify'
For an upcoming audit, I was working through all components with unknown licenses and I found this error. Had to read up on Gradle and the dependency tree to figure out what was going on and why cdxgen is (probably) making this mistake.

Our project has a dependency on `com.android.support:appcompat-v7:26.1.0`, which is being replaced by having a setting `android.enableJetifier=true` in our gradle.properties. This means that when rendering the dependency tree, Gradle outputs this:
`|    +--- com.android.support:appcompat-v7:26.1.0 -> androidx.appcompat:appcompat:1.2.0 (*)`

From what I've seen in the code the last couple of days, cdxgen only expects a version after the '->', so it adds a dependency `com.android.support:appcompat-v7:androidx.appcompat', which simply doesn't exist.

I think I know how and where to fix it, so unless somebody wants to fix it right away, I'll give it a go tonight/tomorrow.

Pull request description:
Fixes #464: Updated the regex to support 'relocation' of a complete component
Fixes #464: Updated the regex to support 'relocation' of a complete component, not just the version.

Patch:
diff --git a/utils.js b/utils.js
index eb5692a2..2ec373d3 100644
--- a/utils.js
+++ b/utils.js
@@ -1449,7 +1449,7 @@ export const parseGradleDep = function (
     }
     let stack = [last_purl];
     const depRegex =
-      /^.*?--- +(?<group>[^\s:]+):(?<name>[^\s:]+)(?::(?:{strictly [[]?)?(?<versionspecified>[^,\s:}]+))?(?:})?(?:[^->]* +-> +(?<versionoverride>[^\s:]+))?/gm;
+      /^.*?--- +(?<groupspecified>[^\s:]+):(?<namespecified>[^\s:]+)(?::(?:{strictly [[]?)?(?<versionspecified>[^,\s:}]+))?(?:})?(?:[^->]* +-> +(?:(?<groupoverride>[^\s:]+):(?<nameoverride>[^\s:]+):)?(?<versionoverride>[^\s:]+))?/gm;
     for (const rline of rawOutput.split("\n")) {
       if (!rline) {
         continue;
@@ -1489,9 +1489,11 @@ export const parseGradleDep = function (
         }
       }
       while ((match = depRegex.exec(rline))) {
-        const [line, group, name, versionspecified, versionoverride] = match;
+        const [line, groupspecified, namespecified, versionspecified, groupoverride, nameoverride, versionoverride] = match;
+        const group = groupoverride || groupspecified;
+        const name = nameoverride || namespecified;
         const version = versionoverride || versionspecified;
-        const level = line.split(group)[0].length / 5;
+        const level = line.split(groupspecified)[0].length / 5;
         if (version !== undefined) {
           let purlString = new PackageURL(
             "maven",


Test patch:
diff --git a/test/data/gradle-android-jetify.dep b/test/data/gradle-android-jetify.dep
new file mode 100644
index 00000000..8822e775
--- /dev/null
+++ b/test/data/gradle-android-jetify.dep
@@ -0,0 +1,2 @@
+\--- com.android.support:appcompat-v7:26.1.0 -> androidx.appcompat:appcompat:1.2.0 (*)
+
diff --git a/utils.test.js b/utils.test.js
index 10d4e7f0..e19fe472 100644
--- a/utils.test.js
+++ b/utils.test.js
@@ -299,6 +299,18 @@ test("parse gradle dependencies", () => {
     readFileSync("./test/data/gradle-android-app.dep", { encoding: "utf-8" })
   );
   expect(parsedList.pkgList.length).toEqual(101);
+  parsedList = parseGradleDep(
+    readFileSync("./test/data/gradle-android-jetify.dep", { encoding: "utf-8" })
+  );
+  expect(parsedList.pkgList.length).toEqual(1);
+  expect(parsedList.pkgList).toEqual([
+    {
+      group: "androidx.appcompat",
+      name: "appcompat",
+      version: "1.2.0",
+      qualifiers: { type: "jar" }
+    }
+  ]);
 });
 
 test("parse gradle projects", () => {