verimu 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { resolve } from "path";
5
+ import { createRequire } from "module";
5
6
 
6
7
  // src/scan.ts
7
8
  import { writeFile } from "fs/promises";
@@ -23,7 +24,7 @@ var VerimuError = class extends Error {
23
24
  var NoLockfileError = class extends VerimuError {
24
25
  constructor(projectPath) {
25
26
  super(
26
- `No supported lockfile found in ${projectPath}. Supported: package-lock.json (npm), packages.lock.json (NuGet), Cargo.lock (Rust), requirements.txt / Pipfile.lock (Python), pom.xml (Maven), go.sum (Go), Gemfile.lock (Ruby)`,
27
+ `No supported lockfile found in ${projectPath}. Supported: package-lock.json (npm), packages.lock.json (NuGet), Cargo.lock (Rust), requirements.txt / Pipfile.lock (Python), pom.xml (Maven), go.sum (Go), Gemfile.lock (Ruby), composer.lock (Composer)`,
27
28
  "NO_LOCKFILE"
28
29
  );
29
30
  this.name = "NoLockfileError";
@@ -58,11 +59,11 @@ var NpmScanner = class {
58
59
  const directNames = /* @__PURE__ */ new Set();
59
60
  if (packageJsonRaw) {
60
61
  try {
61
- const pkg = JSON.parse(packageJsonRaw);
62
- for (const name of Object.keys(pkg.dependencies ?? {})) {
62
+ const pkg2 = JSON.parse(packageJsonRaw);
63
+ for (const name of Object.keys(pkg2.dependencies ?? {})) {
63
64
  directNames.add(name);
64
65
  }
65
- for (const name of Object.keys(pkg.devDependencies ?? {})) {
66
+ for (const name of Object.keys(pkg2.devDependencies ?? {})) {
66
67
  directNames.add(name);
67
68
  }
68
69
  } catch {
@@ -230,14 +231,14 @@ var CargoScanner = class {
230
231
  const directNames = cargoTomlRaw ? this.parseCargoToml(cargoTomlRaw) : /* @__PURE__ */ new Set();
231
232
  const rootName = packages.length > 0 ? packages[0].name : null;
232
233
  const dependencies = [];
233
- for (const pkg of packages) {
234
- if (pkg.name === rootName && pkg.source === void 0) continue;
234
+ for (const pkg2 of packages) {
235
+ if (pkg2.name === rootName && pkg2.source === void 0) continue;
235
236
  dependencies.push({
236
- name: pkg.name,
237
- version: pkg.version,
238
- direct: directNames.has(pkg.name),
237
+ name: pkg2.name,
238
+ version: pkg2.version,
239
+ direct: directNames.has(pkg2.name),
239
240
  ecosystem: "cargo",
240
- purl: this.buildPurl(pkg.name, pkg.version)
241
+ purl: this.buildPurl(pkg2.name, pkg2.version)
241
242
  });
242
243
  }
243
244
  return {
@@ -811,6 +812,75 @@ var RubyScanner = class {
811
812
  }
812
813
  };
813
814
 
815
+ // src/scanners/composer/composer-scanner.ts
816
+ import { readFile as readFile8 } from "fs/promises";
817
+ import { existsSync as existsSync8 } from "fs";
818
+ import path8 from "path";
819
+ var ComposerScanner = class {
820
+ ecosystem = "composer";
821
+ lockfileNames = ["composer.lock"];
822
+ async detect(projectPath) {
823
+ const lockfilePath = path8.join(projectPath, "composer.lock");
824
+ return existsSync8(lockfilePath) ? lockfilePath : null;
825
+ }
826
+ async scan(projectPath, lockfilePath) {
827
+ const [lockRaw, manifestRaw] = await Promise.all([
828
+ readFile8(lockfilePath, "utf-8"),
829
+ readFile8(path8.join(projectPath, "composer.json"), "utf-8").catch(() => null)
830
+ ]);
831
+ const directNames = manifestRaw ? this.parseComposerManifest(manifestRaw) : null;
832
+ const dependencies = this.parseComposerLock(lockRaw, lockfilePath, directNames);
833
+ return {
834
+ projectPath,
835
+ ecosystem: "composer",
836
+ dependencies,
837
+ lockfilePath,
838
+ scannedAt: (/* @__PURE__ */ new Date()).toISOString()
839
+ };
840
+ }
841
+ parseComposerLock(content, lockfilePath, directNames) {
842
+ let lock;
843
+ try {
844
+ lock = JSON.parse(content);
845
+ } catch {
846
+ throw new LockfileParseError(lockfilePath, "Invalid JSON in composer.lock");
847
+ }
848
+ const allPackages = [...lock.packages ?? [], ...lock["packages-dev"] ?? []];
849
+ if (allPackages.length === 0) {
850
+ throw new LockfileParseError(lockfilePath, "No packages found in composer.lock");
851
+ }
852
+ return allPackages.filter((pkg2) => pkg2.name && pkg2.version).map((pkg2) => ({
853
+ name: pkg2.name,
854
+ version: this.normalizeVersion(pkg2.version),
855
+ direct: directNames ? directNames.has(pkg2.name) : true,
856
+ ecosystem: "composer",
857
+ purl: this.buildPurl(pkg2.name, this.normalizeVersion(pkg2.version))
858
+ }));
859
+ }
860
+ parseComposerManifest(content) {
861
+ let manifest;
862
+ try {
863
+ manifest = JSON.parse(content);
864
+ } catch {
865
+ return /* @__PURE__ */ new Set();
866
+ }
867
+ const names = /* @__PURE__ */ new Set();
868
+ for (const section of [manifest.require ?? {}, manifest["require-dev"] ?? {}]) {
869
+ for (const name of Object.keys(section)) {
870
+ if (name === "php" || name.startsWith("ext-") || name.startsWith("lib-")) continue;
871
+ names.add(name);
872
+ }
873
+ }
874
+ return names;
875
+ }
876
+ normalizeVersion(version) {
877
+ return version.trim();
878
+ }
879
+ buildPurl(name, version) {
880
+ return `pkg:composer/${name}@${version}`;
881
+ }
882
+ };
883
+
814
884
  // src/scanners/registry.ts
815
885
  var ScannerRegistry = class {
816
886
  scanners;
@@ -822,7 +892,8 @@ var ScannerRegistry = class {
822
892
  new PipScanner(),
823
893
  new MavenScanner(),
824
894
  new GoScanner(),
825
- new RubyScanner()
895
+ new RubyScanner(),
896
+ new ComposerScanner()
826
897
  ];
827
898
  }
828
899
  /**
@@ -1118,7 +1189,8 @@ var OsvSource = class {
1118
1189
  maven: "Maven",
1119
1190
  pip: "PyPI",
1120
1191
  go: "Go",
1121
- ruby: "RubyGems"
1192
+ ruby: "RubyGems",
1193
+ composer: "Packagist"
1122
1194
  };
1123
1195
  return map[ecosystem] ?? ecosystem;
1124
1196
  }
@@ -1347,7 +1419,8 @@ var VerimuApiClient = class {
1347
1419
  nuget: "nuget",
1348
1420
  go: "gomod",
1349
1421
  cargo: "cargo",
1350
- ruby: "bundler"
1422
+ ruby: "bundler",
1423
+ composer: "composer"
1351
1424
  };
1352
1425
  return map[eco] ?? eco;
1353
1426
  }
@@ -1441,7 +1514,9 @@ function shouldFailCi(report, threshold) {
1441
1514
  }
1442
1515
 
1443
1516
  // src/cli.ts
1444
- var VERSION = "0.0.3";
1517
+ var require2 = createRequire(import.meta.url);
1518
+ var pkg = require2("../package.json");
1519
+ var VERSION = pkg.version ?? "0.0.0";
1445
1520
  var BRAND = `
1446
1521
  \u2566 \u2566\u250C\u2500\u2510\u252C\u2500\u2510\u252C\u250C\u252C\u2510\u252C \u252C
1447
1522
  \u255A\u2557\u2554\u255D\u251C\u2524 \u251C\u252C\u2518\u2502\u2502\u2502\u2502\u2502 \u2502
@@ -1603,7 +1678,7 @@ function printHelp() {
1603
1678
  npm (package-lock.json) pip (requirements.txt)
1604
1679
  Maven (pom.xml) NuGet (packages.lock.json)
1605
1680
  Cargo (Cargo.lock) Go (go.sum)
1606
- Ruby (Gemfile.lock)
1681
+ Ruby (Gemfile.lock) Composer (composer.lock)
1607
1682
 
1608
1683
  Learn more: https://verimu.com
1609
1684
  Dashboard: https://app.verimu.com