socket 1.1.141 → 1.1.142

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cli.js +202 -116
  3. package/dist/cli.js.map +1 -1
  4. package/dist/constants.js +4 -4
  5. package/dist/constants.js.map +1 -1
  6. package/dist/init.gradle +73 -0
  7. package/dist/manifest-scripts/maven-extension/coana-maven-extension.jar +0 -0
  8. package/dist/manifest-scripts/socket-facts.init.gradle +79 -2
  9. package/dist/manifest-scripts/socket-facts.plugin.scala +97 -20
  10. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  11. package/dist/types/commands/manifest/cmd-manifest-auto.d.mts.map +1 -1
  12. package/dist/types/commands/manifest/cmd-manifest-gradle.d.mts.map +1 -1
  13. package/dist/types/commands/manifest/cmd-manifest-kotlin.d.mts.map +1 -1
  14. package/dist/types/commands/manifest/cmd-manifest-maven.d.mts.map +1 -1
  15. package/dist/types/commands/manifest/cmd-manifest-scala.d.mts.map +1 -1
  16. package/dist/types/commands/manifest/convert-gradle-to-facts.d.mts +2 -1
  17. package/dist/types/commands/manifest/convert-gradle-to-facts.d.mts.map +1 -1
  18. package/dist/types/commands/manifest/convert-maven-to-facts.d.mts +2 -1
  19. package/dist/types/commands/manifest/convert-maven-to-facts.d.mts.map +1 -1
  20. package/dist/types/commands/manifest/convert-sbt-to-facts.d.mts +2 -1
  21. package/dist/types/commands/manifest/convert-sbt-to-facts.d.mts.map +1 -1
  22. package/dist/types/commands/manifest/convert_gradle_to_maven.d.mts +2 -1
  23. package/dist/types/commands/manifest/convert_gradle_to_maven.d.mts.map +1 -1
  24. package/dist/types/commands/manifest/generate_auto_manifest.d.mts +4 -1
  25. package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
  26. package/dist/types/commands/manifest/run-manifest-facts.d.mts +2 -1
  27. package/dist/types/commands/manifest/run-manifest-facts.d.mts.map +1 -1
  28. package/dist/types/commands/manifest/scripts/run.d.mts +4 -0
  29. package/dist/types/commands/manifest/scripts/run.d.mts.map +1 -1
  30. package/dist/types/commands/scan/exclude-paths.d.mts +2 -2
  31. package/dist/types/commands/scan/exclude-paths.d.mts.map +1 -1
  32. package/dist/types/commands/scan/handle-create-new-scan.d.mts.map +1 -1
  33. package/package.json +2 -2
@@ -38,6 +38,17 @@ object SocketFactsPlugin extends AutoPlugin {
38
38
  val extracted = Project.extract(st)
39
39
  val allRefs = extracted.structure.allProjectRefs
40
40
 
41
+ // `-Dsocket.excludePaths` (scan-root-relative globs): a subproject whose dir is wholly excluded is
42
+ // never resolved and emits no project record. Source-file-level exclusion is left to the analysis.
43
+ val excludeMatchers = parseExcludeMatchers()
44
+ val rootCanonPath = buildRoot.getCanonicalFile.toPath
45
+ def relOf(f: File): String = {
46
+ val r = rootCanonPath.relativize(f.getCanonicalFile.toPath).toString.replace(java.io.File.separator, "/")
47
+ if (r.isEmpty) "." else r
48
+ }
49
+ def isExcludedRef(ref: ProjectRef): Boolean =
50
+ isExcludedPath(relOf(extracted.get(baseDirectory.in(ref))), excludeMatchers)
51
+
41
52
  // Prefer `updateFull` (coursier `update` returns empty callers); fall back to `update` (sbt 0.13).
42
53
  val hasUpdateFull =
43
54
  extracted.structure.settings.map(_.key.key).exists(_.label == "updateFull")
@@ -53,9 +64,11 @@ object SocketFactsPlugin extends AutoPlugin {
53
64
  val moduleExts = buildModuleExts(allRefs, extracted)
54
65
 
55
66
  allRefs.foreach { ref =>
56
- runUpdateResilient(updateTaskName, ref, extracted, st, failures).foreach { report =>
57
- foldReport(report, ref, extracted, matcher, scannedConfigs, withFiles, populateScope, moduleExts).foreach {
58
- case (rootKey, tree) => perSub(rootKey) = tree
67
+ if (!isExcludedRef(ref)) {
68
+ runUpdateResilient(updateTaskName, ref, extracted, st, failures).foreach { report =>
69
+ foldReport(report, ref, extracted, matcher, scannedConfigs, withFiles, populateScope, moduleExts).foreach {
70
+ case (rootKey, tree) => perSub(rootKey) = tree
71
+ }
59
72
  }
60
73
  }
61
74
  }
@@ -63,12 +76,6 @@ object SocketFactsPlugin extends AutoPlugin {
63
76
  val moduleDirs: Map[String, (Seq[String], Seq[String])] =
64
77
  if (withFiles) buildModuleDirs(allRefs, extracted) else Map.empty
65
78
 
66
- val rootPath = buildRoot.getCanonicalFile.toPath
67
- def relOf(f: File): String = {
68
- val r = rootPath.relativize(f.getCanonicalFile.toPath).toString.replace(java.io.File.separator, "/")
69
- if (r.isEmpty) "." else r
70
- }
71
-
72
79
  val sb = new StringBuilder
73
80
  def rec(fields: String*): Unit = {
74
81
  sb.append(fields.map(esc).mkString("\t")); sb.append('\n')
@@ -76,16 +83,19 @@ object SocketFactsPlugin extends AutoPlugin {
76
83
 
77
84
  rec("meta", "sbt", extracted.getOpt(sbtVersion).getOrElse(""), sys.props.getOrElse("java.version", ""))
78
85
 
79
- // One `project` record per build module (sources/targets only with --with-files).
86
+ // One `project` record per build module (sources/targets only with --with-files). Excluded
87
+ // subprojects are omitted (they were also skipped during resolution above).
80
88
  allRefs.foreach { ref =>
81
- val mid = rootIdOf(extracted, ref)
82
- val ver = if (mid.revision == null) "" else mid.revision
83
- rec("project", ref.project, mid.organization, mid.name, ver, relOf(extracted.get(baseDirectory.in(ref))))
84
- if (withFiles) {
85
- moduleDirs.get(mid.organization + ":" + mid.name + ":" + ver).foreach {
86
- case (sources, targets) =>
87
- sources.foreach(s => rec("projectSrc", ref.project, s))
88
- targets.foreach(t => rec("projectTgt", ref.project, t))
89
+ if (!isExcludedRef(ref)) {
90
+ val mid = rootIdOf(extracted, ref)
91
+ val ver = if (mid.revision == null) "" else mid.revision
92
+ rec("project", ref.project, mid.organization, mid.name, ver, relOf(extracted.get(baseDirectory.in(ref))))
93
+ if (withFiles) {
94
+ moduleDirs.get(mid.organization + ":" + mid.name + ":" + ver).foreach {
95
+ case (sources, targets) =>
96
+ sources.foreach(s => rec("projectSrc", ref.project, s))
97
+ targets.foreach(t => rec("projectTgt", ref.project, t))
98
+ }
89
99
  }
90
100
  }
91
101
  }
@@ -141,6 +151,8 @@ object SocketFactsPlugin extends AutoPlugin {
141
151
 
142
152
  // Absolute source roots + compiled-output dirs per build module, keyed by GAV. --with-files only;
143
153
  // absolute because reachability locates an internal module's code on THIS machine (no registry jar).
154
+ // ALL of the project's configurations are scanned (not just Compile/Test) so custom ones
155
+ // (IntegrationTest, ...) reach the analysis; source-file-level exclusion is coana's job.
144
156
  private def buildModuleDirs(
145
157
  allRefs: Seq[ProjectRef],
146
158
  extracted: Extracted
@@ -148,10 +160,12 @@ object SocketFactsPlugin extends AutoPlugin {
148
160
  allRefs.map { ref =>
149
161
  val mid = rootIdOf(extracted, ref)
150
162
  val ver = if (mid.revision == null) "" else mid.revision
151
- val sources = Seq(Compile, Test)
163
+ val configs: Seq[Configuration] =
164
+ extracted.getOpt(thisProject.in(ref)).map(_.configurations).getOrElse(Seq(Compile, Test))
165
+ val sources = configs
152
166
  .flatMap(c => extracted.getOpt(sourceDirectories.in(ref).in(c)).getOrElse(Nil))
153
167
  .map(_.getAbsolutePath).distinct.sorted
154
- val targets = Seq(Compile, Test)
168
+ val targets = configs
155
169
  .flatMap(c => extracted.getOpt(classDirectory.in(ref).in(c)))
156
170
  .map(_.getAbsolutePath).distinct.sorted
157
171
  (mid.organization + ":" + mid.name + ":" + ver) -> ((sources, targets))
@@ -378,6 +392,69 @@ object SocketFactsPlugin extends AutoPlugin {
378
392
  catch { case _: Throwable => c.toString }
379
393
  }
380
394
 
395
+ // `-Dsocket.excludePaths` → glob PathMatchers, used only to skip whole excluded subprojects. Each
396
+ // entry variant yields the entry itself and `entry/**` so it matches the dir and its subtree (same expansion
397
+ // as the SCA ignore path). A trailing `/**` is stripped first, so a user-written `dir/**` still excludes the
398
+ // `dir` directory itself, not only its contents. Standard glob semantics (anchored to the scan root, matching
399
+ // the CLI flag): `x` is root-level, `**/x` matches at any depth. Mirrors the gradle/maven producers.
400
+ private def parseExcludeMatchers(): Seq[java.nio.file.PathMatcher] = {
401
+ sys.props.get("socket.excludePaths").map(_.trim).filter(_.nonEmpty) match {
402
+ case None => Nil
403
+ case Some(raw) =>
404
+ val fs = java.nio.file.FileSystems.getDefault
405
+ raw.split(",").toSeq.flatMap { r =>
406
+ var g = r.trim.replace("\\", "/")
407
+ while (g.startsWith("/")) g = g.substring(1)
408
+ while (g.endsWith("/")) g = g.substring(0, g.length - 1)
409
+ while (g.endsWith("/**")) {
410
+ g = g.substring(0, g.length - 3)
411
+ while (g.endsWith("/")) g = g.substring(0, g.length - 1)
412
+ }
413
+ if (g.isEmpty) Nil
414
+ else zeroDepthVariants(g).flatMap { v =>
415
+ Seq(fs.getPathMatcher("glob:" + v), fs.getPathMatcher("glob:" + v + "/**"))
416
+ }
417
+ }
418
+ }
419
+ }
420
+
421
+ // NIO glob requires a slash-adjacent `**` to consume at least one path segment, but the CLI's
422
+ // micromatch lets it match zero (`**/x` matches root-level `x`). Emit every variant with `**/`
423
+ // occurrences dropped so both semantics hold.
424
+ private def zeroDepthVariants(glob: String): Seq[String] = {
425
+ val out = mutable.LinkedHashSet[String]()
426
+ val work = mutable.Queue(glob)
427
+ while (work.nonEmpty) {
428
+ val cur = work.dequeue()
429
+ if (out.add(cur)) {
430
+ var idx = cur.indexOf("**/")
431
+ while (idx >= 0) {
432
+ if (idx == 0 || cur.charAt(idx - 1) == '/') {
433
+ val collapsed = cur.substring(0, idx) + cur.substring(idx + 3)
434
+ if (collapsed.nonEmpty) work.enqueue(collapsed)
435
+ }
436
+ idx = cur.indexOf("**/", idx + 1)
437
+ }
438
+ }
439
+ }
440
+ out.toSeq
441
+ }
442
+
443
+ private def isExcludedPath(rel: String, matchers: Seq[java.nio.file.PathMatcher]): Boolean = {
444
+ if (matchers.isEmpty) false
445
+ else {
446
+ var c = (if (rel == null) "" else rel).replace("\\", "/")
447
+ while (c.startsWith("./")) c = c.substring(2)
448
+ while (c.startsWith("/")) c = c.substring(1)
449
+ while (c.endsWith("/")) c = c.substring(0, c.length - 1)
450
+ if (c.isEmpty) false
451
+ else {
452
+ val p = java.nio.file.Paths.get(c)
453
+ matchers.exists(_.matches(p))
454
+ }
455
+ }
456
+ }
457
+
381
458
  private def isTestConf(name: String): Boolean = name.toLowerCase.contains("test")
382
459
 
383
460
  // Only feeds the informational `dev` flag, never gates analysis.