@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.
- package/README.md +33 -14
- package/bin/cdxgen.js +310 -138
- package/bin/evinse.js +22 -0
- package/bin/repl.js +86 -0
- package/bin/sign.js +119 -15
- package/bin/tracebom.js +69 -5
- package/bin/validate.js +107 -19
- package/bin/verify.js +172 -63
- package/data/helpers/init.gradle +46 -21
- package/data/remediations.json +85 -0
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +38 -6
- package/lib/cli/bomAssembly.js +105 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +156 -58
- package/lib/cli/jsBom.js +99 -53
- package/lib/cli/jvmBom.js +708 -147
- package/lib/cli/managedBom.js +415 -224
- package/lib/cli/nativeBom.js +264 -44
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +22 -15
- package/lib/core/fs.js +176 -7
- package/lib/core/httpClient.js +159 -24
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/projectConfig.js +31 -4
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +274 -108
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/caxa.js +434 -2
- package/lib/ecosystems/cmakeResolver.js +76 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +399 -51
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1983 -793
- package/lib/ecosystems/golem.js +28 -12
- package/lib/ecosystems/gradleutils.js +356 -37
- package/lib/ecosystems/jsEvidence.js +104 -44
- package/lib/ecosystems/kosi.js +31 -7
- package/lib/ecosystems/npmutils.js +174 -9
- package/lib/ecosystems/parsers-dotnet.js +616 -159
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +371 -70
- package/lib/ecosystems/parsers-js.js +263 -76
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +204 -12
- package/lib/ecosystems/parsers-misc.js +929 -216
- package/lib/ecosystems/parsers-python.js +167 -24
- package/lib/ecosystems/parsers-rust.js +28 -22
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +1492 -182
- package/lib/ecosystems/rusi.js +54 -10
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +342 -0
- package/lib/ecosystems/scalasem.js +2618 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +1008 -191
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +1101 -222
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/atomUtils.js +703 -43
- package/lib/inventory/auditCategories.js +7 -0
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cdxrs.js +103 -12
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/deps.js +501 -124
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +798 -57
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +90 -6
- package/lib/inventory/evidenceUtils.js +166 -113
- package/lib/inventory/fetchBatch.js +690 -55
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/protobom.js +8 -1
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +45 -27
- package/lib/inventory/spdx.js +101 -0
- package/lib/inventory/traceRunner.js +295 -25
- package/lib/inventory/tracedCrypto.js +294 -0
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +467 -46
- package/lib/managers/oci.js +63 -3
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +466 -0
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +23 -0
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/postgen.js +83 -16
- package/lib/stages/postgen/specVersionCompat.js +32 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +64 -11
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +2 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +23 -23
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +2 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +33 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +24 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +9 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +55 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/metadataProperties.d.ts +39 -0
- package/types/lib/core/metadataProperties.d.ts.map +1 -0
- package/types/lib/core/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +6 -2
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- package/types/lib/ecosystems/bunutils.d.ts +12 -5
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- package/types/lib/ecosystems/caxa.d.ts +14 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +28 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +17 -1
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +70 -4
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +13 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +57 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +54 -2
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +16 -5
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +70 -4
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +53 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +27 -2
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +164 -3
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts +13 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +132 -15
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +280 -15
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +182 -13
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +219 -5
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
- package/types/lib/inventory/cdxrs.d.ts +8 -3
- package/types/lib/inventory/cdxrs.d.ts.map +1 -1
- package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +59 -1
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts +15 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +121 -9
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +10 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +19 -4
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.d.ts.map +1 -1
- package/types/lib/inventory/purl.d.ts +71 -2
- package/types/lib/inventory/purl.d.ts.map +1 -1
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +9 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +59 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +42 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +30 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +29 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +17 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +77 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +52 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +5 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -1
- package/types/lib/parsers/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +18 -1
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -41,6 +41,252 @@ export function applyNugetVersion(pkg, version) {
|
|
|
41
41
|
return applyPurl(pkg, nugetPurl(pkg.name, concrete));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Compare two NuGet versions: up to four numeric release parts (missing parts
|
|
46
|
+
* read as 0), then the prerelease label, with a release sorting after its own
|
|
47
|
+
* prereleases. Build metadata after `+` is ignored, as NuGet ignores it.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} a Version
|
|
50
|
+
* @param {string} b Version
|
|
51
|
+
* @returns {number} Negative, zero or positive, like a sort comparator
|
|
52
|
+
*/
|
|
53
|
+
export function compareNugetVersions(a, b) {
|
|
54
|
+
const split = (version) => {
|
|
55
|
+
const withoutMetadata = `${version ?? ""}`.trim().split("+")[0];
|
|
56
|
+
const dash = withoutMetadata.indexOf("-");
|
|
57
|
+
const release =
|
|
58
|
+
dash >= 0 ? withoutMetadata.slice(0, dash) : withoutMetadata;
|
|
59
|
+
const prerelease = dash >= 0 ? withoutMetadata.slice(dash + 1) : "";
|
|
60
|
+
const parts = release.split(".").map((part) => Number.parseInt(part, 10));
|
|
61
|
+
return { parts, prerelease };
|
|
62
|
+
};
|
|
63
|
+
const left = split(a);
|
|
64
|
+
const right = split(b);
|
|
65
|
+
for (let index = 0; index < 4; index++) {
|
|
66
|
+
const l = Number.isNaN(left.parts[index]) ? 0 : (left.parts[index] ?? 0);
|
|
67
|
+
const r = Number.isNaN(right.parts[index]) ? 0 : (right.parts[index] ?? 0);
|
|
68
|
+
if (l !== r) {
|
|
69
|
+
return l < r ? -1 : 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (left.prerelease === right.prerelease) {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
if (!left.prerelease) {
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
if (!right.prerelease) {
|
|
79
|
+
return -1;
|
|
80
|
+
}
|
|
81
|
+
const leftLabels = left.prerelease.toLowerCase().split(".");
|
|
82
|
+
const rightLabels = right.prerelease.toLowerCase().split(".");
|
|
83
|
+
for (
|
|
84
|
+
let index = 0;
|
|
85
|
+
index < Math.max(leftLabels.length, rightLabels.length);
|
|
86
|
+
index++
|
|
87
|
+
) {
|
|
88
|
+
const l = leftLabels[index];
|
|
89
|
+
const r = rightLabels[index];
|
|
90
|
+
if (l === undefined || r === undefined) {
|
|
91
|
+
return l === undefined ? -1 : 1;
|
|
92
|
+
}
|
|
93
|
+
if (l === r) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const lNumeric = /^\d+$/.test(l);
|
|
97
|
+
const rNumeric = /^\d+$/.test(r);
|
|
98
|
+
if (lNumeric && rNumeric) {
|
|
99
|
+
return Number(l) < Number(r) ? -1 : 1;
|
|
100
|
+
}
|
|
101
|
+
if (lNumeric !== rNumeric) {
|
|
102
|
+
return lNumeric ? -1 : 1;
|
|
103
|
+
}
|
|
104
|
+
return l < r ? -1 : 1;
|
|
105
|
+
}
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Whether a NuGet version range allows a version. A bare version is a minimum
|
|
111
|
+
* (`1.0` means at least 1.0); brackets are inclusive and parentheses exclusive
|
|
112
|
+
* (`[1.0]`, `[1.0,2.0)`, `(,2.0]`). An empty or unparseable range allows
|
|
113
|
+
* anything.
|
|
114
|
+
*
|
|
115
|
+
* @param {string} range Range as a nuspec or lock file states it
|
|
116
|
+
* @param {string} version Version to test
|
|
117
|
+
* @returns {boolean} True when the range allows the version
|
|
118
|
+
*/
|
|
119
|
+
export function nugetRangeAllows(range, version) {
|
|
120
|
+
const text = `${range ?? ""}`.trim();
|
|
121
|
+
if (!text || !version) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
const opening = text[0];
|
|
125
|
+
if (opening !== "[" && opening !== "(") {
|
|
126
|
+
return compareNugetVersions(version, text) >= 0;
|
|
127
|
+
}
|
|
128
|
+
const closing = text[text.length - 1];
|
|
129
|
+
if (closing !== "]" && closing !== ")") {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const inner = text.slice(1, -1);
|
|
133
|
+
const comma = inner.indexOf(",");
|
|
134
|
+
if (comma < 0) {
|
|
135
|
+
return compareNugetVersions(version, inner.trim()) === 0;
|
|
136
|
+
}
|
|
137
|
+
const minimum = inner.slice(0, comma).trim();
|
|
138
|
+
const maximum = inner.slice(comma + 1).trim();
|
|
139
|
+
if (minimum) {
|
|
140
|
+
const order = compareNugetVersions(version, minimum);
|
|
141
|
+
if (order < 0 || (order === 0 && opening === "(")) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (maximum) {
|
|
146
|
+
const order = compareNugetVersions(version, maximum);
|
|
147
|
+
if (order > 0 || (order === 0 && closing === ")")) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Choose the installed version a declared dependency resolves to: the lowest
|
|
156
|
+
* installed version the range allows, as NuGet picks the lowest applicable
|
|
157
|
+
* version; else the only installed version, which is what binding redirects
|
|
158
|
+
* unify a dependency onto. Undefined when nothing installed can be named.
|
|
159
|
+
*
|
|
160
|
+
* @param {string} range Declared range
|
|
161
|
+
* @param {string[]} installedVersions Versions installed for the package
|
|
162
|
+
* @returns {string|undefined} The chosen version
|
|
163
|
+
*/
|
|
164
|
+
export function resolveInstalledNugetVersion(range, installedVersions = []) {
|
|
165
|
+
const allowed = installedVersions
|
|
166
|
+
.filter((version) => nugetRangeAllows(range, version))
|
|
167
|
+
.sort(compareNugetVersions);
|
|
168
|
+
if (allowed.length) {
|
|
169
|
+
return allowed[0];
|
|
170
|
+
}
|
|
171
|
+
return installedVersions.length === 1 ? installedVersions[0] : undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The project directory a .NET manifest belongs to. Restore output records its
|
|
176
|
+
* project file; otherwise project.assets.json sits in the project's `obj/`,
|
|
177
|
+
* and lock files, packages.config and project files sit in the project
|
|
178
|
+
* directory itself.
|
|
179
|
+
*
|
|
180
|
+
* @param {string} manifestFile Manifest path
|
|
181
|
+
* @param {string} [projectPath] Project file the manifest names, when it does
|
|
182
|
+
* @returns {string} Project directory
|
|
183
|
+
*/
|
|
184
|
+
export function dotnetManifestProjectDir(manifestFile, projectPath) {
|
|
185
|
+
if (projectPath) {
|
|
186
|
+
const projectDir = dirname(resolve(projectPath));
|
|
187
|
+
if (safeExistsSync(projectDir)) {
|
|
188
|
+
return projectDir;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const dir = dirname(resolve(manifestFile));
|
|
192
|
+
return basename(dir) === "obj" ? dirname(dir) : dir;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Index the MSBuild properties that props files define, by the directory each
|
|
197
|
+
* file sits in and across the whole scan, so the candidates for every project
|
|
198
|
+
* come from one read of each file.
|
|
199
|
+
*
|
|
200
|
+
* @param {string[]} propsFiles Props files of the scan
|
|
201
|
+
* @returns {{byDir: Object, treeWide: Object}} Property values per directory and
|
|
202
|
+
* across the scan, each a map of property name to values
|
|
203
|
+
*/
|
|
204
|
+
export function indexPropsProperties(propsFiles = []) {
|
|
205
|
+
const byDir = {};
|
|
206
|
+
const treeWide = {};
|
|
207
|
+
for (const propsFile of propsFiles) {
|
|
208
|
+
if (!propsFile) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const nodes = getPropertyGroupTextNodes([propsFile]);
|
|
212
|
+
const dir = dirname(resolve(propsFile));
|
|
213
|
+
byDir[dir] ??= {};
|
|
214
|
+
for (const [key, values] of Object.entries(nodes)) {
|
|
215
|
+
byDir[dir][key] ??= [];
|
|
216
|
+
treeWide[key] ??= [];
|
|
217
|
+
for (const value of values) {
|
|
218
|
+
if (!byDir[dir][key].includes(value)) {
|
|
219
|
+
byDir[dir][key].push(value);
|
|
220
|
+
}
|
|
221
|
+
if (!treeWide[key].includes(value)) {
|
|
222
|
+
treeWide[key].push(value);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return { byDir, treeWide };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The candidate values of MSBuild properties that can apply to a project file,
|
|
232
|
+
* from the props files beside it and above it: the nearest directory that
|
|
233
|
+
* defines a property wins, as the nearest Directory.Build.props is the one
|
|
234
|
+
* MSBuild imports. A property no such directory defines falls back to the
|
|
235
|
+
* values the whole scan's props files give it, which a caller only trusts when
|
|
236
|
+
* there is exactly one.
|
|
237
|
+
*
|
|
238
|
+
* @param {string} projFile Project file
|
|
239
|
+
* @param {{byDir: Object, treeWide: Object}} propsIndex Index built by {@link indexPropsProperties}
|
|
240
|
+
* @returns {Object} Map of property name to candidate values
|
|
241
|
+
*/
|
|
242
|
+
export function projectPropertyCandidates(projFile, propsIndex = {}) {
|
|
243
|
+
const candidates = { ...(propsIndex.treeWide || {}) };
|
|
244
|
+
const settled = new Set();
|
|
245
|
+
let dir = dirname(resolve(projFile));
|
|
246
|
+
for (;;) {
|
|
247
|
+
for (const [key, values] of Object.entries(propsIndex.byDir?.[dir] || {})) {
|
|
248
|
+
if (!settled.has(key)) {
|
|
249
|
+
candidates[key] = values;
|
|
250
|
+
settled.add(key);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const parent = dirname(dir);
|
|
254
|
+
if (parent === dir) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
dir = parent;
|
|
258
|
+
}
|
|
259
|
+
return candidates;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The version of each package that every manifest of a scan agrees on, keyed by
|
|
264
|
+
* lowercased package id. A package that two manifests give different versions
|
|
265
|
+
* is left out: without knowing which project a declaration belongs to, picking
|
|
266
|
+
* one of them would be a guess.
|
|
267
|
+
*
|
|
268
|
+
* @param {Object[]} pkgList Components collected from the scan's manifests
|
|
269
|
+
* @returns {Object} Map of lowercased package id to version
|
|
270
|
+
*/
|
|
271
|
+
export function agreedNugetVersions(pkgList = []) {
|
|
272
|
+
const versions = {};
|
|
273
|
+
for (const p of pkgList) {
|
|
274
|
+
if (!p?.name || !p.version || ["application", "project"].includes(p.type)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const key = p.name.toLowerCase();
|
|
278
|
+
versions[key] ??= new Set();
|
|
279
|
+
versions[key].add(p.version);
|
|
280
|
+
}
|
|
281
|
+
const agreed = {};
|
|
282
|
+
for (const [key, values] of Object.entries(versions)) {
|
|
283
|
+
if (values.size === 1) {
|
|
284
|
+
agreed[key] = [...values][0];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return agreed;
|
|
288
|
+
}
|
|
289
|
+
|
|
44
290
|
/**
|
|
45
291
|
* Method to parse .nupkg files
|
|
46
292
|
*
|
|
@@ -70,9 +316,16 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
70
316
|
const pkg = { group: "" };
|
|
71
317
|
let npkg;
|
|
72
318
|
const dependenciesMap = {};
|
|
319
|
+
// The version range each dependency accepts, per depending package, so a
|
|
320
|
+
// caller holding the installed packages can point an edge at one of them.
|
|
321
|
+
const dependencyRanges = {};
|
|
73
322
|
const addedMap = {};
|
|
74
323
|
try {
|
|
75
|
-
|
|
324
|
+
// A nuspec written on Windows often starts with a UTF-8 byte order mark,
|
|
325
|
+
// which the XML parser rejects as text before the declaration.
|
|
326
|
+
const data =
|
|
327
|
+
nuspecData.charCodeAt(0) === 0xfeff ? nuspecData.slice(1) : nuspecData;
|
|
328
|
+
npkg = xml2js(data, {
|
|
76
329
|
compact: true,
|
|
77
330
|
alwaysArray: false,
|
|
78
331
|
spaces: 4,
|
|
@@ -94,6 +347,7 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
94
347
|
return {
|
|
95
348
|
pkgList,
|
|
96
349
|
dependenciesMap,
|
|
350
|
+
dependencyRanges,
|
|
97
351
|
};
|
|
98
352
|
}
|
|
99
353
|
const m = npkg.metadata;
|
|
@@ -101,7 +355,12 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
101
355
|
pkg.version = m.version._;
|
|
102
356
|
pkg.description = m.description._;
|
|
103
357
|
applyPurl(pkg, nugetPurl(pkg.name, pkg.version));
|
|
104
|
-
|
|
358
|
+
// A licence expression is the machine-readable licence NuGet records; the
|
|
359
|
+
// licence URL is the older, often unresolvable form, so the expression wins.
|
|
360
|
+
if (m.license?.$?.type === "expression" && m.license?._?.trim()) {
|
|
361
|
+
pkg.license = findLicenseId(m.license._.trim()) || m.license._.trim();
|
|
362
|
+
}
|
|
363
|
+
if (!pkg.license && m.licenseUrl) {
|
|
105
364
|
pkg.license = findLicenseId(m.licenseUrl._);
|
|
106
365
|
}
|
|
107
366
|
if (m.authors) {
|
|
@@ -128,18 +387,19 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
128
387
|
};
|
|
129
388
|
pkg.scope = "required";
|
|
130
389
|
pkgList.push(pkg);
|
|
390
|
+
const ranges = {};
|
|
131
391
|
if (m?.dependencies?.dependency) {
|
|
132
392
|
const dependsOn = [];
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
} else {
|
|
139
|
-
const d = m.dependencies.dependency.$;
|
|
393
|
+
const declared = Array.isArray(m.dependencies.dependency)
|
|
394
|
+
? m.dependencies.dependency
|
|
395
|
+
: [m.dependencies.dependency];
|
|
396
|
+
for (const adep of declared) {
|
|
397
|
+
const d = adep.$;
|
|
140
398
|
dependsOn.push(d.id);
|
|
399
|
+
ranges[d.id] ??= d.version;
|
|
141
400
|
}
|
|
142
401
|
dependenciesMap[pkg["bom-ref"]] = dependsOn;
|
|
402
|
+
dependencyRanges[pkg["bom-ref"]] = ranges;
|
|
143
403
|
} else if (m?.dependencies?.group) {
|
|
144
404
|
let dependencyGroups;
|
|
145
405
|
if (Array.isArray(m.dependencies.group)) {
|
|
@@ -168,6 +428,7 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
168
428
|
continue;
|
|
169
429
|
}
|
|
170
430
|
groupPkg.name = agroupdep.id;
|
|
431
|
+
ranges[agroupdep.id] ??= agroupdep.version;
|
|
171
432
|
let declaredRange;
|
|
172
433
|
if (agroupdep?.version) {
|
|
173
434
|
let versionStr = agroupdep.version;
|
|
@@ -225,11 +486,13 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
225
486
|
} // for
|
|
226
487
|
} // group dependency block
|
|
227
488
|
dependenciesMap[pkg["bom-ref"]] = dependsOn;
|
|
489
|
+
dependencyRanges[pkg["bom-ref"]] = ranges;
|
|
228
490
|
} // for
|
|
229
491
|
}
|
|
230
492
|
return {
|
|
231
493
|
pkgList,
|
|
232
494
|
dependenciesMap,
|
|
495
|
+
dependencyRanges,
|
|
233
496
|
};
|
|
234
497
|
}
|
|
235
498
|
|
|
@@ -289,7 +552,7 @@ export function parseCsPkgData(pkgData, pkgFile, pkgNameVersions = {}) {
|
|
|
289
552
|
// Backfill from a version already resolved by a more precise manifest.
|
|
290
553
|
// Concrete versions are never overridden - a disagreement means both
|
|
291
554
|
// versions must be tracked.
|
|
292
|
-
pkg.version = pkgNameVersions
|
|
555
|
+
pkg.version = lookupNugetVersion(pkgNameVersions, pkg.name);
|
|
293
556
|
}
|
|
294
557
|
applyNugetVersion(pkg, pkg.version);
|
|
295
558
|
if (pkgFile) {
|
|
@@ -466,16 +729,130 @@ export function getPropertyGroupTextNodes(propsFiles) {
|
|
|
466
729
|
return matches;
|
|
467
730
|
}
|
|
468
731
|
|
|
732
|
+
/**
|
|
733
|
+
* Read the trimmed text of an MSBuild property from a parsed PropertyGroup.
|
|
734
|
+
*
|
|
735
|
+
* @param {Object} propertyGroup PropertyGroup parsed by xml2js in compact mode
|
|
736
|
+
* @param {string} key Property name
|
|
737
|
+
* @returns {string|undefined} The text, or undefined when absent or empty
|
|
738
|
+
*/
|
|
739
|
+
function propertyGroupText(propertyGroup, key) {
|
|
740
|
+
const text = propertyGroup?.[key]?.[0]?._?.[0];
|
|
741
|
+
if (typeof text !== "string" || !text.trim().length) {
|
|
742
|
+
return undefined;
|
|
743
|
+
}
|
|
744
|
+
return text.trim();
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Look up a package version in a name - version map. NuGet package ids are
|
|
749
|
+
* case-insensitive, so a map may be keyed by the id as written or lowercased.
|
|
750
|
+
*
|
|
751
|
+
* @param {Object} versions Map of package id to version
|
|
752
|
+
* @param {string} name Package id
|
|
753
|
+
* @returns {string|undefined} The version, or undefined when the map has none
|
|
754
|
+
*/
|
|
755
|
+
export function lookupNugetVersion(versions, name) {
|
|
756
|
+
if (!versions || !name) {
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
return versions[name] ?? versions[name.toLowerCase()];
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Collect the MSBuild properties a project file defines itself, from every
|
|
764
|
+
* PropertyGroup, keyed by property name. A later definition wins, as it does
|
|
765
|
+
* when MSBuild evaluates the file.
|
|
766
|
+
*
|
|
767
|
+
* @param {Object} project Project element parsed by xml2js in compact mode
|
|
768
|
+
* @returns {Object} Map of property name to text value
|
|
769
|
+
*/
|
|
770
|
+
function projectOwnProperties(project) {
|
|
771
|
+
const properties = {};
|
|
772
|
+
for (const propertyGroup of project?.PropertyGroup || []) {
|
|
773
|
+
for (const key of Object.keys(propertyGroup)) {
|
|
774
|
+
if (key === "$" || key === "value") {
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
const text = propertyGroupText(propertyGroup, key);
|
|
778
|
+
if (text !== undefined) {
|
|
779
|
+
properties[key] = text;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return properties;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Evaluate MSBuild properties of one project with a single `dotnet msbuild`
|
|
788
|
+
* call. Asking for every property at once costs one evaluation per project,
|
|
789
|
+
* where one call per package reference evaluated the same project over and
|
|
790
|
+
* over.
|
|
791
|
+
*
|
|
792
|
+
* @param {string} projFile Project file
|
|
793
|
+
* @param {string[]} names Property names
|
|
794
|
+
* @returns {Object} Map of property name to evaluated value, without empty values
|
|
795
|
+
*/
|
|
796
|
+
function evaluateMsbuildProperties(projFile, names) {
|
|
797
|
+
const values = {};
|
|
798
|
+
if (!projFile || !names.length) {
|
|
799
|
+
return values;
|
|
800
|
+
}
|
|
801
|
+
const result = safeSpawnSync(
|
|
802
|
+
DOTNET_CMD,
|
|
803
|
+
[
|
|
804
|
+
"msbuild",
|
|
805
|
+
projFile,
|
|
806
|
+
"-nologo",
|
|
807
|
+
...names.map((name) => `-getProperty:${name}`),
|
|
808
|
+
],
|
|
809
|
+
{ shell: isWin },
|
|
810
|
+
);
|
|
811
|
+
if (result.status !== 0 || result.error || !result.stdout?.trim()) {
|
|
812
|
+
return values;
|
|
813
|
+
}
|
|
814
|
+
const stdout = result.stdout.trim();
|
|
815
|
+
if (names.length === 1) {
|
|
816
|
+
values[names[0]] = stdout;
|
|
817
|
+
return values;
|
|
818
|
+
}
|
|
819
|
+
// Several properties come back as one JSON document.
|
|
820
|
+
try {
|
|
821
|
+
const evaluated = JSON.parse(stdout)?.Properties || {};
|
|
822
|
+
for (const name of names) {
|
|
823
|
+
if (typeof evaluated[name] === "string" && evaluated[name].trim()) {
|
|
824
|
+
values[name] = evaluated[name].trim();
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
} catch (_e) {
|
|
828
|
+
// Unexpected output: treat every property as unresolved.
|
|
829
|
+
}
|
|
830
|
+
return values;
|
|
831
|
+
}
|
|
832
|
+
|
|
469
833
|
/**
|
|
470
834
|
* Method to parse .csproj like xml files
|
|
471
835
|
*
|
|
836
|
+
* A version the project file does not state is taken, in order, from the
|
|
837
|
+
* versions this project restored, from central package management, and last
|
|
838
|
+
* from a version the whole scan agrees on. Two projects of one tree routinely
|
|
839
|
+
* restore different versions of a package, so a version taken from another
|
|
840
|
+
* project would describe a package this project does not use.
|
|
841
|
+
*
|
|
472
842
|
* @param {String} csProjData Raw data
|
|
473
843
|
* @param {String} projFile File name
|
|
474
|
-
* @param {Object} pkgNameVersions
|
|
844
|
+
* @param {Object} pkgNameVersions Versions this project restored (its project.assets.json,
|
|
845
|
+
* packages.lock.json or packages.config), keyed by package id or lowercased id
|
|
475
846
|
* @param {Boolean} msbuildInstalled Whether msbuild is available to resolve properties
|
|
476
|
-
* @param {Object} pkgVersionLabelCandidates Candidate values for msbuild version properties
|
|
847
|
+
* @param {Object} pkgVersionLabelCandidates Candidate values for msbuild version properties,
|
|
848
|
+
* from the props files that can apply to this project
|
|
477
849
|
* @param {Object} centralVersions Versions declared centrally in Directory.Packages.props,
|
|
478
850
|
* keyed by lowercased package id. See {@link getCentralPackageVersions}.
|
|
851
|
+
* @param {Object} fallbackVersions Versions every project of the scan agrees on, keyed by
|
|
852
|
+
* lowercased package id, used only when nothing closer states one
|
|
853
|
+
* @param {Object} restoredNames Package ids as this project's restore output spells them,
|
|
854
|
+
* keyed by lowercased id. NuGet ids are case-insensitive, so a reference spelled
|
|
855
|
+
* differently names the same package and takes the restored spelling.
|
|
479
856
|
*
|
|
480
857
|
* @returns {Object} Containing parent component, package, and dependencies
|
|
481
858
|
*/
|
|
@@ -486,6 +863,8 @@ export function parseCsProjData(
|
|
|
486
863
|
msbuildInstalled = false,
|
|
487
864
|
pkgVersionLabelCandidates = {},
|
|
488
865
|
centralVersions = {},
|
|
866
|
+
fallbackVersions = {},
|
|
867
|
+
restoredNames = {},
|
|
489
868
|
) {
|
|
490
869
|
const pkgList = [];
|
|
491
870
|
const parentComponent = { type: "application", properties: [] };
|
|
@@ -514,6 +893,68 @@ export function parseCsProjData(
|
|
|
514
893
|
return pkgList;
|
|
515
894
|
}
|
|
516
895
|
const project = projects[0];
|
|
896
|
+
const restoredName = (name) => restoredNames[name.toLowerCase()] || name;
|
|
897
|
+
const resolvedVersion = (name) =>
|
|
898
|
+
lookupNugetVersion(pkgNameVersions, name) ||
|
|
899
|
+
lookupNugetVersion(centralVersions, name) ||
|
|
900
|
+
lookupNugetVersion(fallbackVersions, name);
|
|
901
|
+
// `$(Name)` version labels: the project's own properties, then the props
|
|
902
|
+
// files that can apply to it, then (only for what neither settles) one
|
|
903
|
+
// msbuild evaluation of the project.
|
|
904
|
+
const ownProperties = projectOwnProperties(project);
|
|
905
|
+
const labelOf = (version) => version?.match(/^\$\((.*)\)$/)?.[1];
|
|
906
|
+
const staticLabelValue = (label) =>
|
|
907
|
+
ownProperties[label] ??
|
|
908
|
+
(pkgVersionLabelCandidates[label]?.length === 1
|
|
909
|
+
? pkgVersionLabelCandidates[label][0]
|
|
910
|
+
: undefined);
|
|
911
|
+
let msbuildValues = {};
|
|
912
|
+
if (msbuildInstalled) {
|
|
913
|
+
const unresolved = new Set();
|
|
914
|
+
for (const item of project.ItemGroup || []) {
|
|
915
|
+
for (const reference of item.PackageReference || []) {
|
|
916
|
+
const label = labelOf(
|
|
917
|
+
reference.$?.VersionOverride ||
|
|
918
|
+
reference.VersionOverride?.[0]._?.[0] ||
|
|
919
|
+
reference.$?.Version ||
|
|
920
|
+
reference.Version?.[0]._?.[0],
|
|
921
|
+
);
|
|
922
|
+
if (label && staticLabelValue(label) === undefined) {
|
|
923
|
+
unresolved.add(label);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
msbuildValues = evaluateMsbuildProperties(projFile, [...unresolved].sort());
|
|
928
|
+
}
|
|
929
|
+
// SDK-style projects declare their version through the MSBuild properties
|
|
930
|
+
// that `dotnet pack` reads: PackageVersion, which defaults to Version, which
|
|
931
|
+
// in turn defaults to VersionPrefix plus an optional `-VersionSuffix`. A
|
|
932
|
+
// property may be set in any PropertyGroup, so they are collected first.
|
|
933
|
+
const sdkVersionProps = {};
|
|
934
|
+
for (const apg of project?.PropertyGroup || []) {
|
|
935
|
+
for (const key of [
|
|
936
|
+
"PackageVersion",
|
|
937
|
+
"Version",
|
|
938
|
+
"VersionPrefix",
|
|
939
|
+
"VersionSuffix",
|
|
940
|
+
]) {
|
|
941
|
+
const value = propertyGroupText(apg, key);
|
|
942
|
+
if (value !== undefined) {
|
|
943
|
+
sdkVersionProps[key] = value;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
let sdkVersion =
|
|
948
|
+
sdkVersionProps.PackageVersion ||
|
|
949
|
+
sdkVersionProps.Version ||
|
|
950
|
+
(sdkVersionProps.VersionPrefix
|
|
951
|
+
? `${sdkVersionProps.VersionPrefix}${sdkVersionProps.VersionSuffix ? `-${sdkVersionProps.VersionSuffix}` : ""}`
|
|
952
|
+
: undefined);
|
|
953
|
+
// An MSBuild property reference such as $(BuildNumber) is only known at
|
|
954
|
+
// build time, so a version that still contains one is not reported.
|
|
955
|
+
if (sdkVersion?.includes("$(")) {
|
|
956
|
+
sdkVersion = undefined;
|
|
957
|
+
}
|
|
517
958
|
// First make up a parentcomponent name based on the .csproj file name
|
|
518
959
|
if (projFile) {
|
|
519
960
|
parentComponent.name = basename(projFile).replaceAll(
|
|
@@ -571,10 +1012,6 @@ export function parseCsProjData(
|
|
|
571
1012
|
if (outputType === "Library") {
|
|
572
1013
|
parentComponent.type = "library";
|
|
573
1014
|
}
|
|
574
|
-
applyPurl(
|
|
575
|
-
parentComponent,
|
|
576
|
-
nugetPurl(parentComponent.name, parentComponent.version || "latest"),
|
|
577
|
-
);
|
|
578
1015
|
// The MSBuild OutputType (Exe, WinExe, …) used to ride along as an
|
|
579
1016
|
// `output_type` purl qualifier, which nuget does not define — every such
|
|
580
1017
|
// purl was invalid. It is project metadata, so it belongs in properties.
|
|
@@ -686,53 +1123,30 @@ export function parseCsProjData(
|
|
|
686
1123
|
if (!pref.Include || pref.Include.includes(".csproj")) {
|
|
687
1124
|
continue;
|
|
688
1125
|
}
|
|
689
|
-
pkg.name = pref.Include;
|
|
1126
|
+
pkg.name = restoredName(pref.Include);
|
|
690
1127
|
// Under central package management a PackageReference carries no Version at
|
|
691
1128
|
// all, and VersionOverride is the documented way for a project to opt out of
|
|
692
|
-
// the central version, so it wins over everything else.
|
|
693
|
-
// is
|
|
694
|
-
//
|
|
695
|
-
// more precise than a central declaration that may be a floating range.
|
|
1129
|
+
// the central version, so it wins over everything else. Otherwise the version
|
|
1130
|
+
// this project restored is more precise than a central declaration that may
|
|
1131
|
+
// be a floating range.
|
|
696
1132
|
pkg.version =
|
|
697
1133
|
pref.VersionOverride ||
|
|
698
1134
|
item.PackageReference[j].VersionOverride?.[0]._?.[0] ||
|
|
699
1135
|
pref.Version ||
|
|
700
1136
|
item.PackageReference[j].Version?.[0]._?.[0] ||
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
if (
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
);
|
|
715
|
-
if (
|
|
716
|
-
result.status === 0 &&
|
|
717
|
-
!result.error &&
|
|
718
|
-
result.stdout.trim()
|
|
719
|
-
) {
|
|
720
|
-
pkg.version = result.stdout.trim();
|
|
721
|
-
version_resolved = true;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
if (!version_resolved) {
|
|
725
|
-
if (
|
|
726
|
-
pkgVersionLabelCandidates[version_label_match]?.length === 1
|
|
727
|
-
) {
|
|
728
|
-
// Prioritizing correctness over completeness: reject resolved package version label if it has more than one possible values.
|
|
729
|
-
pkg.version = pkgVersionLabelCandidates[version_label_match][0];
|
|
730
|
-
} else if (DEBUG_MODE) {
|
|
731
|
-
console.log(
|
|
732
|
-
`Could not resolve package version label ${version_label_match} for ${pkg.name}`,
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
1137
|
+
resolvedVersion(pkg.name);
|
|
1138
|
+
const versionLabel = labelOf(pkg.version);
|
|
1139
|
+
if (versionLabel) {
|
|
1140
|
+
// Prioritizing correctness over completeness: a label with more than one
|
|
1141
|
+
// candidate value across the applicable props files stays unresolved.
|
|
1142
|
+
const labelValue =
|
|
1143
|
+
msbuildValues[versionLabel] ?? staticLabelValue(versionLabel);
|
|
1144
|
+
if (labelValue !== undefined) {
|
|
1145
|
+
pkg.version = labelValue;
|
|
1146
|
+
} else if (DEBUG_MODE) {
|
|
1147
|
+
console.log(
|
|
1148
|
+
`Could not resolve package version label ${versionLabel} for ${pkg.name}`,
|
|
1149
|
+
);
|
|
736
1150
|
}
|
|
737
1151
|
}
|
|
738
1152
|
// A `Version` attribute holds whatever the project declares, which may
|
|
@@ -749,9 +1163,7 @@ export function parseCsProjData(
|
|
|
749
1163
|
pkg.version = exactPin[1];
|
|
750
1164
|
} else if (!concreteVersion(pkg.version)) {
|
|
751
1165
|
declaredRange = pkg.version;
|
|
752
|
-
pkg.version =
|
|
753
|
-
pkgNameVersions[pkg.name] ||
|
|
754
|
-
centralVersions[pkg.name.toLowerCase()];
|
|
1166
|
+
pkg.version = resolvedVersion(pkg.name);
|
|
755
1167
|
}
|
|
756
1168
|
}
|
|
757
1169
|
// A version that could not be resolved from any source must not be
|
|
@@ -826,21 +1238,20 @@ export function parseCsProjData(
|
|
|
826
1238
|
}
|
|
827
1239
|
}
|
|
828
1240
|
}
|
|
1241
|
+
pkg.name = restoredName(pkg.name);
|
|
829
1242
|
let declaredAssemblyVersion;
|
|
830
1243
|
if (incParts.length > 1 && incParts[1].includes("Version")) {
|
|
831
1244
|
const declared = incParts[1].replace("Version=", "").trim();
|
|
832
|
-
// An assembly reference carries the version inline,
|
|
833
|
-
//
|
|
834
|
-
//
|
|
835
|
-
//
|
|
836
|
-
//
|
|
1245
|
+
// An assembly reference carries the assembly's version inline, which is
|
|
1246
|
+
// not the version of the package that ships it (Newtonsoft.Json 13.0.3
|
|
1247
|
+
// ships assembly 13.0.0.0), and can be an MSBuild property such as
|
|
1248
|
+
// `Version=$(TargetFSharpCoreVersion)` that only a build evaluates. A
|
|
1249
|
+
// concrete one is kept as the assembly version; a property as a
|
|
1250
|
+
// declaration.
|
|
837
1251
|
if (declared && !concreteVersion(declared)) {
|
|
838
1252
|
declaredAssemblyVersion = declared;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
centralVersions[pkg.name.toLowerCase()];
|
|
842
|
-
} else {
|
|
843
|
-
assemblyVersion = declared || pkgNameVersions[pkg.name];
|
|
1253
|
+
} else if (declared) {
|
|
1254
|
+
assemblyVersion = declared;
|
|
844
1255
|
}
|
|
845
1256
|
}
|
|
846
1257
|
if (declaredAssemblyVersion) {
|
|
@@ -849,7 +1260,11 @@ export function parseCsProjData(
|
|
|
849
1260
|
value: declaredAssemblyVersion,
|
|
850
1261
|
});
|
|
851
1262
|
}
|
|
852
|
-
|
|
1263
|
+
// The package version comes from the HintPath's package folder, or from
|
|
1264
|
+
// what this project restored; never from the assembly version, and not
|
|
1265
|
+
// from a central pin, which applies to PackageReference items only.
|
|
1266
|
+
const version =
|
|
1267
|
+
hintVersion ?? lookupNugetVersion(pkgNameVersions, pkg.name);
|
|
853
1268
|
// An assembly reference that states no version anywhere - no HintPath to
|
|
854
1269
|
// read one from and no `Version=` on the Include - leaves the component
|
|
855
1270
|
// versionless in both fields. The registry's latest release is not a
|
|
@@ -877,7 +1292,7 @@ export function parseCsProjData(
|
|
|
877
1292
|
value: assemblyName,
|
|
878
1293
|
});
|
|
879
1294
|
}
|
|
880
|
-
if (
|
|
1295
|
+
if (assemblyVersion) {
|
|
881
1296
|
pkg.properties.push({
|
|
882
1297
|
name: "cdx:dotnet:assembly_version",
|
|
883
1298
|
value: assemblyVersion,
|
|
@@ -924,21 +1339,29 @@ export function parseCsProjData(
|
|
|
924
1339
|
}
|
|
925
1340
|
}
|
|
926
1341
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
)
|
|
1342
|
+
if (sdkVersion) {
|
|
1343
|
+
parentComponent.version = sdkVersion;
|
|
1344
|
+
} else if (
|
|
1345
|
+
!parentComponent.version &&
|
|
1346
|
+
!Object.keys(sdkVersionProps).length &&
|
|
1347
|
+
(project.$?.Sdk || project.Sdk)
|
|
1348
|
+
) {
|
|
1349
|
+
// An SDK-style project that sets no version builds as 1.0.0, the Version
|
|
1350
|
+
// its project.assets.json records too, so both describe one component. A
|
|
1351
|
+
// version set from a build-time property is unknown, not 1.0.0.
|
|
1352
|
+
parentComponent.version = "1.0.0";
|
|
933
1353
|
}
|
|
934
|
-
|
|
935
|
-
|
|
1354
|
+
// The purl is built once every PropertyGroup has been read, so a version
|
|
1355
|
+
// declared after OutputType is not lost. A project that states no version
|
|
1356
|
+
// gets a versionless purl: "latest" is not a version.
|
|
1357
|
+
if (parentComponent.name) {
|
|
1358
|
+
applyNugetVersion(parentComponent, parentComponent.version);
|
|
936
1359
|
}
|
|
937
1360
|
let dependencies = [];
|
|
938
1361
|
if (parentComponent?.["bom-ref"]) {
|
|
939
1362
|
dependencies = [
|
|
940
1363
|
{
|
|
941
|
-
ref: parentComponent
|
|
1364
|
+
ref: parentComponent["bom-ref"],
|
|
942
1365
|
dependsOn: [...new Set(pkgList.map((p) => p["bom-ref"]))].sort(),
|
|
943
1366
|
},
|
|
944
1367
|
];
|
|
@@ -950,6 +1373,41 @@ export function parseCsProjData(
|
|
|
950
1373
|
};
|
|
951
1374
|
}
|
|
952
1375
|
|
|
1376
|
+
// The package folders a consuming project compiles against or loads at run
|
|
1377
|
+
// time. A DLL elsewhere in the package (build/, buildTransitive/, tools/,
|
|
1378
|
+
// analyzers/) is a build-time helper of the package itself, such as the
|
|
1379
|
+
// System.Formats.Asn1.dll coverlet.collector carries for its test-platform
|
|
1380
|
+
// collector: the project's code never calls it, so its name must not credit
|
|
1381
|
+
// the package with the project's framework calls (issue 4441).
|
|
1382
|
+
const DOTNET_REFERENCED_ASSET_FOLDERS = new Set(["lib", "ref", "runtimes"]);
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* Whether a file of a NuGet package is an assembly a consuming project can
|
|
1386
|
+
* reference: a .dll, .exe, or .so under lib/, ref/, or runtimes/.
|
|
1387
|
+
*
|
|
1388
|
+
* @param {string} packageFile Path of the file inside the package, as project.assets.json lists it
|
|
1389
|
+
* @returns {boolean} true for a referenced assembly
|
|
1390
|
+
*/
|
|
1391
|
+
export function isReferencedDotnetPackageFile(packageFile) {
|
|
1392
|
+
if (typeof packageFile !== "string") {
|
|
1393
|
+
return false;
|
|
1394
|
+
}
|
|
1395
|
+
const lowerFile = packageFile.toLowerCase();
|
|
1396
|
+
if (
|
|
1397
|
+
!lowerFile.endsWith(".dll") &&
|
|
1398
|
+
!lowerFile.endsWith(".exe") &&
|
|
1399
|
+
!lowerFile.endsWith(".so")
|
|
1400
|
+
) {
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
const normalized = lowerFile.replaceAll("\\", "/");
|
|
1404
|
+
const slashIndex = normalized.indexOf("/");
|
|
1405
|
+
return (
|
|
1406
|
+
slashIndex > 0 &&
|
|
1407
|
+
DOTNET_REFERENCED_ASSET_FOLDERS.has(normalized.slice(0, slashIndex))
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
|
|
953
1411
|
/**
|
|
954
1412
|
* Parse a .NET project.assets.json file and return the package list and dependency tree.
|
|
955
1413
|
*
|
|
@@ -959,7 +1417,8 @@ export function parseCsProjData(
|
|
|
959
1417
|
*
|
|
960
1418
|
* @param {string} csProjData Raw JSON string of the project.assets.json file
|
|
961
1419
|
* @param {string} assetsJsonFile Path to the project.assets.json file, used for evidence properties
|
|
962
|
-
* @returns {{ pkgList: Object[], dependenciesList: Object[] }}
|
|
1420
|
+
* @returns {{ pkgList: Object[], dependenciesList: Object[], projectPath: (string|undefined) }}
|
|
1421
|
+
* `projectPath` is the project file the restore output belongs to, as restore recorded it
|
|
963
1422
|
*/
|
|
964
1423
|
export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
|
|
965
1424
|
// extract name, operator, version from .NET package representation
|
|
@@ -999,22 +1458,18 @@ export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
|
|
|
999
1458
|
return { pkgList, dependenciesList };
|
|
1000
1459
|
}
|
|
1001
1460
|
csProjData = JSON.parse(csProjData);
|
|
1002
|
-
|
|
1461
|
+
const projectPath = csProjData.project?.restore?.projectPath;
|
|
1462
|
+
let rootRef;
|
|
1003
1463
|
if (csProjData.project?.restore?.projectName) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
namespace: "" || null,
|
|
1007
|
-
name: csProjData.project?.restore?.projectName,
|
|
1008
|
-
version: csProjData.project.version || "latest" || null,
|
|
1009
|
-
});
|
|
1464
|
+
// The project's own version as restore evaluated it; "latest" is not a
|
|
1465
|
+
// version, so a project without one gets a versionless purl.
|
|
1010
1466
|
rootPkg = {
|
|
1011
1467
|
group: "",
|
|
1012
1468
|
name: csProjData.project.restore.projectName,
|
|
1013
|
-
version: csProjData.project.version || "latest",
|
|
1014
1469
|
type: "application",
|
|
1015
|
-
purl: purlString,
|
|
1016
|
-
"bom-ref": decodeURIComponent(purlString),
|
|
1017
1470
|
};
|
|
1471
|
+
applyNugetVersion(rootPkg, csProjData.project.version);
|
|
1472
|
+
rootRef = rootPkg["bom-ref"];
|
|
1018
1473
|
pkgList.push(rootPkg);
|
|
1019
1474
|
}
|
|
1020
1475
|
const rootPkgDeps = new Set();
|
|
@@ -1028,53 +1483,42 @@ export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
|
|
|
1028
1483
|
if (nameOperatorVersion == null) {
|
|
1029
1484
|
continue;
|
|
1030
1485
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
//
|
|
1034
|
-
//
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
break;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
if (!matchFound) {
|
|
1053
|
-
if (DEBUG_MODE) {
|
|
1054
|
-
console.log(
|
|
1055
|
-
"Unable to match",
|
|
1056
|
-
dependencyName,
|
|
1057
|
-
"with a target name. The dependency tree will be imprecise.",
|
|
1058
|
-
);
|
|
1059
|
-
}
|
|
1060
|
-
continue;
|
|
1486
|
+
// A direct dependency is declared as a constraint (`Moq >= 4.17.6`,
|
|
1487
|
+
// `X >= 7.0.0-*`, `[4.0.0, 5.0.0)`), and restore installs one version of
|
|
1488
|
+
// each package per target: the edge points at that installed version,
|
|
1489
|
+
// whatever the constraint's lower bound says.
|
|
1490
|
+
const resolvedTarget = Object.keys(
|
|
1491
|
+
csProjData.targets[frameworkTarget] || {},
|
|
1492
|
+
).find(
|
|
1493
|
+
(targetKey) =>
|
|
1494
|
+
targetKey.split("/")[0].toLowerCase() ===
|
|
1495
|
+
nameOperatorVersion.name.toLowerCase(),
|
|
1496
|
+
);
|
|
1497
|
+
if (!resolvedTarget) {
|
|
1498
|
+
if (DEBUG_MODE) {
|
|
1499
|
+
console.log(
|
|
1500
|
+
"Unable to match",
|
|
1501
|
+
dependencyName,
|
|
1502
|
+
"with a target name. The dependency tree will be imprecise.",
|
|
1503
|
+
);
|
|
1061
1504
|
}
|
|
1505
|
+
continue;
|
|
1062
1506
|
}
|
|
1063
|
-
|
|
1507
|
+
const [nameToUse, resolvedVersion] = resolvedTarget.split("/");
|
|
1064
1508
|
const dpurl = decodeURIComponent(
|
|
1065
1509
|
build({
|
|
1066
1510
|
type: "nuget",
|
|
1067
1511
|
namespace: "" || null,
|
|
1068
1512
|
name: nameToUse,
|
|
1069
|
-
version:
|
|
1513
|
+
version: resolvedVersion || null,
|
|
1070
1514
|
}),
|
|
1071
1515
|
);
|
|
1072
1516
|
rootPkgDeps.add(dpurl);
|
|
1073
1517
|
}
|
|
1074
1518
|
}
|
|
1075
|
-
if (
|
|
1519
|
+
if (rootRef && rootPkgDeps.size) {
|
|
1076
1520
|
dependenciesList.push({
|
|
1077
|
-
ref:
|
|
1521
|
+
ref: rootRef,
|
|
1078
1522
|
dependsOn: Array.from(rootPkgDeps).sort(),
|
|
1079
1523
|
});
|
|
1080
1524
|
}
|
|
@@ -1113,12 +1557,8 @@ export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
|
|
|
1113
1557
|
if (lib[rootDep].files && Array.isArray(lib[rootDep].files)) {
|
|
1114
1558
|
const dllFiles = new Set();
|
|
1115
1559
|
lib[rootDep].files.forEach((f) => {
|
|
1116
|
-
if (
|
|
1117
|
-
f.
|
|
1118
|
-
f.endsWith(".exe") ||
|
|
1119
|
-
f.endsWith(".so")
|
|
1120
|
-
) {
|
|
1121
|
-
dllFiles.add(basename(f));
|
|
1560
|
+
if (isReferencedDotnetPackageFile(f)) {
|
|
1561
|
+
dllFiles.add(basename(f.replaceAll("\\", "/")));
|
|
1122
1562
|
}
|
|
1123
1563
|
});
|
|
1124
1564
|
pkg.properties = [
|
|
@@ -1205,6 +1645,7 @@ export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
|
|
|
1205
1645
|
return {
|
|
1206
1646
|
pkgList,
|
|
1207
1647
|
dependenciesList,
|
|
1648
|
+
projectPath,
|
|
1208
1649
|
};
|
|
1209
1650
|
}
|
|
1210
1651
|
|
|
@@ -1280,39 +1721,55 @@ export function parseCsPkgLockData(csLockData, pkgLockFile) {
|
|
|
1280
1721
|
}
|
|
1281
1722
|
const dependsOn = new Set();
|
|
1282
1723
|
if (libData.dependencies) {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
(assetData.dependencies[aversionNoRuntime]?.[adep.toLowerCase()] &&
|
|
1301
|
-
assetData.dependencies[aversionNoRuntime][adep.toLowerCase()]
|
|
1302
|
-
.type === "Project")
|
|
1303
|
-
) {
|
|
1304
|
-
adepResolvedVersion = undefined;
|
|
1305
|
-
adep = adep.toLowerCase();
|
|
1306
|
-
} else if (DEBUG_MODE) {
|
|
1307
|
-
console.warn(
|
|
1308
|
-
`Unable to find the resolved version for ${adep} ${aversion}. Using ${adepResolvedVersion} which may be incorrect.`,
|
|
1724
|
+
const aversionNoRuntime = aversion.split("/")[0];
|
|
1725
|
+
// The entry for a dependency: in this target, the target without its
|
|
1726
|
+
// runtime identifier, or a runtime-specific target of the same
|
|
1727
|
+
// framework. Package ids are case-insensitive, and the lock file writes
|
|
1728
|
+
// a dependency the way the depending package's nuspec spells it. See
|
|
1729
|
+
// #930 and #937.
|
|
1730
|
+
const sections = [
|
|
1731
|
+
assetData.dependencies[aversion],
|
|
1732
|
+
assetData.dependencies[aversionNoRuntime],
|
|
1733
|
+
...Object.keys(assetData.dependencies)
|
|
1734
|
+
.filter((key) => key.startsWith(`${aversionNoRuntime}/`))
|
|
1735
|
+
.map((key) => assetData.dependencies[key]),
|
|
1736
|
+
].filter(Boolean);
|
|
1737
|
+
const entryFor = (name) => {
|
|
1738
|
+
for (const section of sections) {
|
|
1739
|
+
const key = Object.keys(section).find(
|
|
1740
|
+
(candidate) => candidate.toLowerCase() === name.toLowerCase(),
|
|
1309
1741
|
);
|
|
1742
|
+
if (key) {
|
|
1743
|
+
return { name: key, entry: section[key] };
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
return undefined;
|
|
1747
|
+
};
|
|
1748
|
+
for (const adep of Object.keys(libData.dependencies)) {
|
|
1749
|
+
const found = entryFor(adep);
|
|
1750
|
+
let depName;
|
|
1751
|
+
let depVersion;
|
|
1752
|
+
if (found?.entry?.type === "Project") {
|
|
1753
|
+
depName = found.name;
|
|
1754
|
+
} else if (found?.entry?.resolved) {
|
|
1755
|
+
depName = found.name;
|
|
1756
|
+
depVersion = found.entry.resolved;
|
|
1757
|
+
} else {
|
|
1758
|
+
// The dependency value is the declared range (`[6.0.0, )`), which
|
|
1759
|
+
// names no package version: without a resolved entry there is no
|
|
1760
|
+
// component to point at.
|
|
1761
|
+
if (DEBUG_MODE) {
|
|
1762
|
+
console.warn(
|
|
1763
|
+
`Unable to find the resolved version for ${adep} ${aversion}. The dependency tree will be imprecise.`,
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
continue;
|
|
1310
1767
|
}
|
|
1311
1768
|
const adpurl = build({
|
|
1312
1769
|
type: "nuget",
|
|
1313
1770
|
namespace: "" || null,
|
|
1314
|
-
name:
|
|
1315
|
-
version:
|
|
1771
|
+
name: depName,
|
|
1772
|
+
version: depVersion || null,
|
|
1316
1773
|
});
|
|
1317
1774
|
dependsOn.add(decodeURIComponent(adpurl));
|
|
1318
1775
|
}
|