@cdxgen/cdxgen 13.2.0 → 13.4.0

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 (311) hide show
  1. package/README.md +33 -14
  2. package/bin/cdxgen.js +310 -138
  3. package/bin/evinse.js +22 -0
  4. package/bin/repl.js +86 -0
  5. package/bin/sign.js +119 -15
  6. package/bin/tracebom.js +69 -5
  7. package/bin/validate.js +107 -19
  8. package/bin/verify.js +172 -63
  9. package/data/helpers/init.gradle +46 -21
  10. package/data/remediations.json +85 -0
  11. package/data/rules/dependency-sources.yaml +67 -0
  12. package/data/rules/scala-evidence.yaml +115 -0
  13. package/lib/audit/index.js +38 -6
  14. package/lib/cli/bomAssembly.js +105 -15
  15. package/lib/cli/cliOptions.js +93 -1
  16. package/lib/cli/index.js +156 -58
  17. package/lib/cli/jsBom.js +99 -53
  18. package/lib/cli/jvmBom.js +708 -147
  19. package/lib/cli/managedBom.js +415 -224
  20. package/lib/cli/nativeBom.js +264 -44
  21. package/lib/core/activity.js +12 -0
  22. package/lib/core/env.js +22 -15
  23. package/lib/core/fs.js +176 -7
  24. package/lib/core/httpClient.js +159 -24
  25. package/lib/core/metadataProperties.js +97 -0
  26. package/lib/core/pluginRun.js +184 -0
  27. package/lib/core/processTree.js +100 -0
  28. package/lib/core/projectConfig.js +31 -4
  29. package/lib/core/runState.js +39 -0
  30. package/lib/core/toml.js +72 -0
  31. package/lib/ecosystems/asarutils.js +4 -2
  32. package/lib/ecosystems/bunutils.js +274 -108
  33. package/lib/ecosystems/cargoCache.js +231 -8
  34. package/lib/ecosystems/caxa.js +434 -2
  35. package/lib/ecosystems/cmakeResolver.js +76 -21
  36. package/lib/ecosystems/cppBuildContext.js +631 -0
  37. package/lib/ecosystems/cppEvidence.js +399 -51
  38. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  39. package/lib/ecosystems/denoutils.js +93 -66
  40. package/lib/ecosystems/ecosystems.js +1983 -793
  41. package/lib/ecosystems/golem.js +28 -12
  42. package/lib/ecosystems/gradleutils.js +356 -37
  43. package/lib/ecosystems/jsEvidence.js +104 -44
  44. package/lib/ecosystems/kosi.js +31 -7
  45. package/lib/ecosystems/npmutils.js +174 -9
  46. package/lib/ecosystems/parsers-dotnet.js +616 -159
  47. package/lib/ecosystems/parsers-elm.js +46 -28
  48. package/lib/ecosystems/parsers-gleam.js +3 -4
  49. package/lib/ecosystems/parsers-go.js +371 -70
  50. package/lib/ecosystems/parsers-js.js +263 -76
  51. package/lib/ecosystems/parsers-julia.js +2 -3
  52. package/lib/ecosystems/parsers-jvm.js +204 -12
  53. package/lib/ecosystems/parsers-misc.js +929 -216
  54. package/lib/ecosystems/parsers-python.js +167 -24
  55. package/lib/ecosystems/parsers-rust.js +28 -22
  56. package/lib/ecosystems/parsers-terraform.js +1573 -19
  57. package/lib/ecosystems/pythonutils.js +102 -6
  58. package/lib/ecosystems/remote/huggingface.js +3 -0
  59. package/lib/ecosystems/rubyutils.js +1492 -182
  60. package/lib/ecosystems/rusi.js +54 -10
  61. package/lib/ecosystems/sbtutils.js +243 -187
  62. package/lib/ecosystems/scalacliutils.js +342 -0
  63. package/lib/ecosystems/scalasem.js +2618 -0
  64. package/lib/ecosystems/terraformRegistry.js +288 -0
  65. package/lib/ecosystems/utils.js +2 -0
  66. package/lib/ecosystems/vendoredCode.js +156 -0
  67. package/lib/evinser/evinser.js +1008 -191
  68. package/lib/evinser/swiftsem.js +1914 -302
  69. package/lib/helpers/agenticToolutils.js +2 -2
  70. package/lib/helpers/bomSigner.js +1101 -222
  71. package/lib/inventory/aiCollector.js +4 -1
  72. package/lib/inventory/analyzer.js +110 -127
  73. package/lib/inventory/atomUtils.js +703 -43
  74. package/lib/inventory/auditCategories.js +7 -0
  75. package/lib/inventory/buildToolRateLimit.js +144 -0
  76. package/lib/inventory/cacheCommands.js +2 -1
  77. package/lib/inventory/cdxrs.js +103 -12
  78. package/lib/inventory/cmakeBuildDirs.js +254 -0
  79. package/lib/inventory/deps.js +501 -124
  80. package/lib/inventory/depsUtils.js +183 -11
  81. package/lib/inventory/display.js +4 -5
  82. package/lib/inventory/dosai.js +798 -57
  83. package/lib/inventory/dosaiParsers.js +310 -15
  84. package/lib/inventory/dynamic.js +90 -6
  85. package/lib/inventory/evidenceUtils.js +166 -113
  86. package/lib/inventory/fetchBatch.js +690 -55
  87. package/lib/inventory/fetchDiskCache.js +597 -0
  88. package/lib/inventory/forgeEnricher.js +14 -5
  89. package/lib/inventory/jvmLocalRepos.js +917 -0
  90. package/lib/inventory/mcpConfigParser.js +2 -3
  91. package/lib/inventory/parentSelection.js +146 -0
  92. package/lib/inventory/protobom.js +8 -1
  93. package/lib/inventory/purl.js +152 -3
  94. package/lib/inventory/rustFormulationParser.js +3 -4
  95. package/lib/inventory/sbomDocument.js +2 -70
  96. package/lib/inventory/scalaCoords.js +153 -0
  97. package/lib/inventory/source.js +45 -27
  98. package/lib/inventory/spdx.js +101 -0
  99. package/lib/inventory/traceRunner.js +295 -25
  100. package/lib/inventory/tracedCrypto.js +294 -0
  101. package/lib/managers/binary.js +115 -24
  102. package/lib/managers/docker.js +467 -46
  103. package/lib/managers/oci.js +63 -3
  104. package/lib/parsers/cmakeCache.js +69 -0
  105. package/lib/parsers/cmakeLists.js +466 -0
  106. package/lib/parsers/cmakePresets.js +400 -0
  107. package/lib/parsers/compileCommands.js +557 -0
  108. package/lib/parsers/largeJson.js +454 -0
  109. package/lib/parsers/npmrc.js +19 -1
  110. package/lib/parsers/strictJson.js +322 -0
  111. package/lib/parsers/terraformConfig.js +1073 -0
  112. package/lib/parsers/terraformSource.js +652 -0
  113. package/lib/server/server.js +23 -0
  114. package/lib/stages/postgen/introspection/markers.js +1 -1
  115. package/lib/stages/postgen/postgen.js +83 -16
  116. package/lib/stages/postgen/specVersionCompat.js +32 -0
  117. package/lib/validator/bomValidator.js +6 -16
  118. package/lib/validator/index.js +64 -11
  119. package/lib/validator/reporters/console.js +3 -0
  120. package/lib/validator/reporters/json.js +2 -0
  121. package/lib/validator/reporters/sarif.js +7 -0
  122. package/package.json +23 -23
  123. package/types/lib/audit/index.d.ts.map +1 -1
  124. package/types/lib/cli/bomAssembly.d.ts +2 -1
  125. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  126. package/types/lib/cli/cliOptions.d.ts +33 -1
  127. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  128. package/types/lib/cli/index.d.ts.map +1 -1
  129. package/types/lib/cli/jsBom.d.ts.map +1 -1
  130. package/types/lib/cli/jvmBom.d.ts +24 -1
  131. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  132. package/types/lib/cli/managedBom.d.ts +7 -4
  133. package/types/lib/cli/managedBom.d.ts.map +1 -1
  134. package/types/lib/cli/nativeBom.d.ts +3 -1
  135. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  136. package/types/lib/core/activity.d.ts.map +1 -1
  137. package/types/lib/core/env.d.ts +9 -0
  138. package/types/lib/core/env.d.ts.map +1 -1
  139. package/types/lib/core/fs.d.ts +55 -0
  140. package/types/lib/core/fs.d.ts.map +1 -1
  141. package/types/lib/core/httpClient.d.ts +13 -8
  142. package/types/lib/core/httpClient.d.ts.map +1 -1
  143. package/types/lib/core/metadataProperties.d.ts +39 -0
  144. package/types/lib/core/metadataProperties.d.ts.map +1 -0
  145. package/types/lib/core/pluginRun.d.ts +97 -0
  146. package/types/lib/core/pluginRun.d.ts.map +1 -0
  147. package/types/lib/core/processTree.d.ts +36 -0
  148. package/types/lib/core/processTree.d.ts.map +1 -0
  149. package/types/lib/core/projectConfig.d.ts +6 -2
  150. package/types/lib/core/projectConfig.d.ts.map +1 -1
  151. package/types/lib/core/runState.d.ts +29 -0
  152. package/types/lib/core/runState.d.ts.map +1 -0
  153. package/types/lib/core/toml.d.ts +20 -0
  154. package/types/lib/core/toml.d.ts.map +1 -0
  155. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  156. package/types/lib/ecosystems/bunutils.d.ts +12 -5
  157. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  158. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  159. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  160. package/types/lib/ecosystems/caxa.d.ts +14 -0
  161. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  162. package/types/lib/ecosystems/cmakeResolver.d.ts +28 -3
  163. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  164. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  165. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  166. package/types/lib/ecosystems/cppEvidence.d.ts +17 -1
  167. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  168. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  169. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  170. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  171. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  172. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  173. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  174. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  175. package/types/lib/ecosystems/gradleutils.d.ts +70 -4
  176. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  177. package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
  178. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  179. package/types/lib/ecosystems/kosi.d.ts +13 -0
  180. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  181. package/types/lib/ecosystems/npmutils.d.ts +57 -0
  182. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  183. package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
  184. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  185. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  186. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  187. package/types/lib/ecosystems/parsers-go.d.ts +54 -2
  188. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  189. package/types/lib/ecosystems/parsers-js.d.ts +16 -5
  190. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  191. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  192. package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
  193. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  194. package/types/lib/ecosystems/parsers-misc.d.ts +70 -4
  195. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  196. package/types/lib/ecosystems/parsers-python.d.ts +53 -3
  197. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  198. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  199. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  200. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  201. package/types/lib/ecosystems/pythonutils.d.ts +27 -2
  202. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  203. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  204. package/types/lib/ecosystems/rubyutils.d.ts +164 -3
  205. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/rusi.d.ts +13 -0
  207. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  208. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  209. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  210. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  211. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  212. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  213. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  214. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  215. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  216. package/types/lib/ecosystems/utils.d.ts +2 -2
  217. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  218. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  219. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  220. package/types/lib/evinser/evinser.d.ts +132 -15
  221. package/types/lib/evinser/evinser.d.ts.map +1 -1
  222. package/types/lib/evinser/swiftsem.d.ts +280 -15
  223. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  224. package/types/lib/helpers/bomSigner.d.ts +182 -13
  225. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  226. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  227. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  228. package/types/lib/inventory/atomUtils.d.ts +219 -5
  229. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  230. package/types/lib/inventory/auditCategories.d.ts +3 -0
  231. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  232. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  233. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  234. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  235. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  236. package/types/lib/inventory/cdxrs.d.ts +8 -3
  237. package/types/lib/inventory/cdxrs.d.ts.map +1 -1
  238. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  239. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  240. package/types/lib/inventory/deps.d.ts +59 -1
  241. package/types/lib/inventory/deps.d.ts.map +1 -1
  242. package/types/lib/inventory/depsUtils.d.ts +15 -0
  243. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  244. package/types/lib/inventory/display.d.ts.map +1 -1
  245. package/types/lib/inventory/dosai.d.ts +121 -9
  246. package/types/lib/inventory/dosai.d.ts.map +1 -1
  247. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  248. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  249. package/types/lib/inventory/dynamic.d.ts +10 -0
  250. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  251. package/types/lib/inventory/evidenceUtils.d.ts +19 -4
  252. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  253. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  254. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  255. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  256. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  257. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  258. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  259. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  260. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/parentSelection.d.ts +34 -0
  262. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  263. package/types/lib/inventory/plugins.d.ts.map +1 -1
  264. package/types/lib/inventory/protobom.d.ts.map +1 -1
  265. package/types/lib/inventory/purl.d.ts +71 -2
  266. package/types/lib/inventory/purl.d.ts.map +1 -1
  267. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  268. package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
  269. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  270. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  271. package/types/lib/inventory/source.d.ts.map +1 -1
  272. package/types/lib/inventory/spdx.d.ts +9 -0
  273. package/types/lib/inventory/spdx.d.ts.map +1 -1
  274. package/types/lib/inventory/traceRunner.d.ts +59 -1
  275. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  276. package/types/lib/inventory/tracedCrypto.d.ts +42 -0
  277. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  278. package/types/lib/managers/binary.d.ts +30 -1
  279. package/types/lib/managers/binary.d.ts.map +1 -1
  280. package/types/lib/managers/docker.d.ts +29 -0
  281. package/types/lib/managers/docker.d.ts.map +1 -1
  282. package/types/lib/managers/oci.d.ts +17 -1
  283. package/types/lib/managers/oci.d.ts.map +1 -1
  284. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  285. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  286. package/types/lib/parsers/cmakeLists.d.ts +77 -0
  287. package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
  288. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  289. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  290. package/types/lib/parsers/compileCommands.d.ts +115 -0
  291. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  292. package/types/lib/parsers/largeJson.d.ts +52 -0
  293. package/types/lib/parsers/largeJson.d.ts.map +1 -0
  294. package/types/lib/parsers/npmrc.d.ts +5 -0
  295. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  296. package/types/lib/parsers/strictJson.d.ts +46 -0
  297. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  298. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  299. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  300. package/types/lib/parsers/terraformSource.d.ts +66 -0
  301. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  302. package/types/lib/server/server.d.ts.map +1 -1
  303. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  304. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  305. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  306. package/types/lib/validator/index.d.ts +18 -1
  307. package/types/lib/validator/index.d.ts.map +1 -1
  308. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  309. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  310. package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
  311. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
@@ -0,0 +1,342 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { delimiter, join } from "node:path";
3
+
4
+ import { DEBUG_MODE } from "../core/activity.js";
5
+ import { commandOutputText } from "../core/buildLedger.js";
6
+ import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
7
+ import { isWin } from "../core/paths.js";
8
+ import { noteBuildToolRateLimit } from "../inventory/buildToolRateLimit.js";
9
+ import { parseScalaArtifact } from "../inventory/scalaCoords.js";
10
+ import { completeComponent } from "./parsers-jvm.js";
11
+
12
+ // The scala-cli directive syntax, at the top of project.scala or any
13
+ // .scala/.sc file: //> using <key> <values...>
14
+ const DIRECTIVE_REGEX = /^\s*\/\/>\s*using\s+(\S+)\s+(.+)$/;
15
+ const DEP_KEYS = new Set([
16
+ "dep",
17
+ "deps",
18
+ "dependency",
19
+ "dependencies",
20
+ "test.dep",
21
+ "test.deps",
22
+ ]);
23
+
24
+ function scalaBinaryVersion(scalaVersion) {
25
+ if (!scalaVersion) {
26
+ return null;
27
+ }
28
+ if (scalaVersion.startsWith("3")) {
29
+ return "3";
30
+ }
31
+ if (scalaVersion.startsWith("2.13")) {
32
+ return "2.13";
33
+ }
34
+ if (scalaVersion.startsWith("2.12")) {
35
+ return "2.12";
36
+ }
37
+ const match = scalaVersion.match(/^2\.(\d+)/);
38
+ return match ? `2.${match[1]}` : null;
39
+ }
40
+
41
+ /**
42
+ * Parse the `//> using` directives of a scala-cli source file.
43
+ *
44
+ * @param {string} sourceFile Path of the source file
45
+ * @returns {{ scalaVersion: string|null, platform: string|null, nativeVersion: string|null, deps: Object[] }}
46
+ * The declared scala version and platform, and the declared dependencies as
47
+ * `{ group, artifact, version, cross, test }` entries, where `cross` is
48
+ * `::`, `:::` or `none`
49
+ */
50
+ export function parseScalaCliDirectives(sourceFile) {
51
+ const result = {
52
+ scalaVersion: null,
53
+ platform: null,
54
+ nativeVersion: null,
55
+ deps: [],
56
+ };
57
+ let content;
58
+ try {
59
+ content = readFileSync(sourceFile, "utf-8");
60
+ } catch (_err) {
61
+ return result;
62
+ }
63
+ for (const line of content.split(/\r?\n/)) {
64
+ const match = DIRECTIVE_REGEX.exec(line);
65
+ if (!match) {
66
+ continue;
67
+ }
68
+ const key = match[1].toLowerCase();
69
+ const values = match[2]
70
+ .match(/"[^"]*"|\S+/g)
71
+ ?.map((v) => v.replaceAll('"', ""))
72
+ .filter(Boolean);
73
+ if (!values?.length) {
74
+ continue;
75
+ }
76
+ if (key === "scala") {
77
+ result.scalaVersion = values[0];
78
+ } else if (key === "platform") {
79
+ result.platform = values[0];
80
+ } else if (key === "scalanativeversion" || key === "nativeversion") {
81
+ result.nativeVersion = values[0];
82
+ } else if (DEP_KEYS.has(key)) {
83
+ for (const value of values) {
84
+ // group:artifact:version, group::artifact:version (binary version)
85
+ // and group:::artifact:version (full cross version)
86
+ const depMatch = /^([^:]+)(:::|::|:)([^:]+):(.+)$/.exec(value);
87
+ if (depMatch) {
88
+ result.deps.push({
89
+ group: depMatch[1],
90
+ artifact: depMatch[3],
91
+ version: depMatch[4],
92
+ cross: depMatch[2] === ":" ? "none" : depMatch[2],
93
+ test: key.startsWith("test."),
94
+ });
95
+ } else if (DEBUG_MODE) {
96
+ console.log(`Skipping the malformed scala-cli dependency ${value}`);
97
+ }
98
+ }
99
+ }
100
+ }
101
+ return result;
102
+ }
103
+
104
+ /**
105
+ * Build a component for a scala-cli dependency in the sbt purl form: the
106
+ * Scala binary suffix is not part of the name, the platform suffix of the
107
+ * declared platform is, and the Scala binary version is recorded as
108
+ * cdx:scala:compilerVersion.
109
+ *
110
+ * @param {Object} dep Parsed dependency declaration
111
+ * @param {Object} project Directives of the file the dependency was declared in
112
+ * @param {string} sourceFile File the dependency was declared in
113
+ * @returns {Object|null} The component, or null for malformed declarations
114
+ */
115
+ export function scalaCliComponent(dep, project, sourceFile) {
116
+ let platformSuffix = "";
117
+ if (project.platform === "scala-js") {
118
+ platformSuffix = "_sjs1";
119
+ } else if (project.platform === "scala-native" && project.nativeVersion) {
120
+ const nativeMatch = project.nativeVersion.match(/^(0\.\d+)/);
121
+ if (nativeMatch) {
122
+ platformSuffix = `_native${nativeMatch[1]}`;
123
+ }
124
+ }
125
+ // `::` lets the tool append the binary suffix, which the sbt form drops;
126
+ // `:::` appends the full Scala version, which the sbt form keeps. A single
127
+ // colon names the published artifact as is, so an explicit `_3` suffix is
128
+ // stripped like the sbt purls do.
129
+ let name = `${dep.artifact}${platformSuffix}`;
130
+ let binaryVersion = scalaBinaryVersion(project.scalaVersion);
131
+ if (dep.cross === ":::" && project.scalaVersion) {
132
+ name = `${name}_${project.scalaVersion}`;
133
+ } else if (dep.cross === "none") {
134
+ const scalaInfo = parseScalaArtifact(dep.artifact);
135
+ name = scalaInfo.purlName;
136
+ binaryVersion = scalaInfo.binaryVersion;
137
+ }
138
+ const component = completeComponent({
139
+ group: dep.group,
140
+ name,
141
+ version: dep.version,
142
+ });
143
+ component.scope = dep.test ? "optional" : undefined;
144
+ component.evidence = {
145
+ identity: {
146
+ field: "purl",
147
+ confidence: 1,
148
+ methods: [
149
+ {
150
+ technique: "manifest-analysis",
151
+ confidence: 1,
152
+ value: sourceFile,
153
+ },
154
+ ],
155
+ },
156
+ };
157
+ // Only the Scala-published artifacts carry the compiler version; a plain
158
+ // Java artifact declared with a single colon does not.
159
+ if (binaryVersion) {
160
+ component.properties = [
161
+ {
162
+ name: "cdx:scala:compilerVersion",
163
+ value: binaryVersion,
164
+ },
165
+ ];
166
+ }
167
+ return component;
168
+ }
169
+
170
+ /**
171
+ * Map a jar path of the Coursier cache to its Maven coordinates.
172
+ *
173
+ * Only the https cache layout with a well-known repository path segment is
174
+ * parsed; anything else returns null rather than guessing a group id.
175
+ *
176
+ * @param {string} jarPath Path of a jar in the Coursier cache
177
+ * @returns {{ group: string, name: string, version: string }|null} The coordinates
178
+ */
179
+ export function coordinatesFromCoursierPath(jarPath) {
180
+ if (!jarPath) {
181
+ return null;
182
+ }
183
+ const segments = jarPath.split(/[\\/]/).filter(Boolean);
184
+ const repoMarkerIndex = segments.findIndex((segment) =>
185
+ ["maven2", "maven", "releases", "snapshots", "central"].includes(segment),
186
+ );
187
+ if (repoMarkerIndex === -1) {
188
+ return null;
189
+ }
190
+ const version = segments[segments.length - 2];
191
+ const artifactDir = segments[segments.length - 3];
192
+ const jarName = segments[segments.length - 1].replace(/\.jar$/, "");
193
+ const name = jarName.endsWith(`-${version}`)
194
+ ? jarName.slice(0, -`-${version}`.length)
195
+ : artifactDir;
196
+ if (!name || !version) {
197
+ return null;
198
+ }
199
+ const groupSegments = segments.slice(
200
+ repoMarkerIndex + 1,
201
+ segments.length - 3,
202
+ );
203
+ if (!groupSegments.length) {
204
+ return null;
205
+ }
206
+ return {
207
+ group: groupSegments.join("."),
208
+ name,
209
+ version,
210
+ };
211
+ }
212
+
213
+ function scalaCliCommandArgs() {
214
+ // scala-cli is the standalone tool; the scala runner of the same toolchain
215
+ // wraps it behind --power. Without --server=false the compile goes through
216
+ // a Bloop daemon that outlives the scan. The project is the working
217
+ // directory, so its path never reaches the shell that starts the tool on
218
+ // Windows.
219
+ const compileArgs = ["compile", "--server=false", "--print-class-path", "."];
220
+ const scalaCliProbe = safeSpawnSync(
221
+ "scala-cli",
222
+ ["version", "--cli-version"],
223
+ {
224
+ shell: isWin,
225
+ },
226
+ );
227
+ if (!scalaCliProbe.error && scalaCliProbe.status === 0) {
228
+ return { cmd: "scala-cli", args: compileArgs };
229
+ }
230
+ return { cmd: "scala", args: ["--power", ...compileArgs] };
231
+ }
232
+
233
+ /**
234
+ * Collect the components a scala-cli project declares through its
235
+ * `//> using` directives.
236
+ *
237
+ * Transitive dependencies are added from the class path of
238
+ * `scala-cli compile --print-class-path` when dependency installation is
239
+ * allowed, by mapping the Coursier cache paths back to coordinates.
240
+ *
241
+ * @param {string} dirPath Directory of the scala-cli project
242
+ * @param {Object} options CLI options
243
+ * @returns {Object[]} Component list, empty when the project declares no
244
+ * scala-cli directives
245
+ */
246
+ export function collectScalaCliComponents(dirPath, options = {}) {
247
+ const sourceFiles = [
248
+ join(dirPath, "project.scala"),
249
+ ...getAllFiles(dirPath, "*.scala"),
250
+ ...getAllFiles(dirPath, "*.sc"),
251
+ ].filter((file) => safeExistsSync(file));
252
+ const seenFiles = new Set();
253
+ const projects = [];
254
+ for (const file of sourceFiles) {
255
+ if (seenFiles.has(file)) {
256
+ continue;
257
+ }
258
+ seenFiles.add(file);
259
+ const directives = parseScalaCliDirectives(file);
260
+ if (directives.deps.length || directives.scalaVersion) {
261
+ projects.push({ file, directives });
262
+ }
263
+ }
264
+ if (!projects.length) {
265
+ return [];
266
+ }
267
+ const pkgList = [];
268
+ const seenPurls = new Set();
269
+ const addComponent = (component) => {
270
+ if (component?.purl && !seenPurls.has(component.purl)) {
271
+ seenPurls.add(component.purl);
272
+ pkgList.push(component);
273
+ }
274
+ };
275
+ for (const { file, directives } of projects) {
276
+ for (const dep of directives.deps) {
277
+ addComponent(scalaCliComponent(dep, directives, file));
278
+ }
279
+ }
280
+ if (!pkgList.length) {
281
+ return pkgList;
282
+ }
283
+ // The transitive dependencies of the declared ones come from the class
284
+ // path the tool itself resolves; the compile requires installs to be
285
+ // allowed.
286
+ if (options.installDeps === false) {
287
+ console.log(
288
+ "Skipping the scala-cli class path resolution since dependency installation is disabled.",
289
+ );
290
+ return pkgList;
291
+ }
292
+ const { cmd, args } = scalaCliCommandArgs();
293
+ console.log(`Executing '${cmd} ${args.join(" ")}' in`, dirPath);
294
+ const result = safeSpawnSync(cmd, args, {
295
+ cwd: dirPath,
296
+ shell: isWin,
297
+ maxBuffer: 100 * 1024 * 1024,
298
+ timeout: 600_000,
299
+ });
300
+ // scala-cli resolves through Coursier, so the class path fails with its
301
+ // downloader message when the repository rate limits the machine.
302
+ noteBuildToolRateLimit("scala-cli", commandOutputText(result), {
303
+ command: `${cmd} ${args.join(" ")}`,
304
+ exitCode: typeof result.status === "number" ? result.status : undefined,
305
+ });
306
+ const classPath = (result.stdout || "")
307
+ .trim()
308
+ .split("\n")
309
+ .filter((line) => line.includes(".jar"))
310
+ .pop();
311
+ if (!classPath) {
312
+ if (DEBUG_MODE) {
313
+ console.log("The scala-cli class path could not be determined.");
314
+ }
315
+ return pkgList;
316
+ }
317
+ for (const jarPath of classPath.split(delimiter)) {
318
+ if (!jarPath.endsWith(".jar")) {
319
+ continue;
320
+ }
321
+ const coordinates = coordinatesFromCoursierPath(jarPath);
322
+ if (!coordinates) {
323
+ continue;
324
+ }
325
+ const scalaInfo = parseScalaArtifact(coordinates.name);
326
+ const component = completeComponent({
327
+ group: coordinates.group,
328
+ name: scalaInfo.purlName,
329
+ version: coordinates.version,
330
+ });
331
+ if (scalaInfo.binaryVersion) {
332
+ component.properties = [
333
+ {
334
+ name: "cdx:scala:compilerVersion",
335
+ value: scalaInfo.binaryVersion,
336
+ },
337
+ ];
338
+ }
339
+ addComponent(component);
340
+ }
341
+ return pkgList;
342
+ }