@cdxgen/cdxgen 13.5.0 → 13.7.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 +17 -10
- package/bin/audit.js +7 -4
- package/bin/cdxgen.js +260 -37
- package/bin/convert.js +146 -22
- package/bin/evinse.js +28 -3
- package/bin/repl.js +47 -3
- package/bin/sign.js +211 -34
- package/bin/tracebom.js +18 -6
- package/bin/validate.js +24 -3
- package/bin/verify.js +113 -5
- package/data/behavior-taxonomy.schema.json +1491 -0
- package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
- package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
- package/data/license-aliases.json +24 -2
- package/data/pqc-migration.json +239 -0
- package/data/remediations.json +176 -0
- package/data/rules/ai-bom.yaml +1 -1
- package/data/rules/brotli-decoder.yaml +107 -0
- package/data/rules/cbom-security.yaml +4 -3
- package/data/rules/package-integrity.yaml +28 -0
- package/data/rules/vscode-extensions.yaml +75 -0
- package/data/spdx-license-list.json +121 -7
- package/data/spdx-licenses.json +69 -0
- package/data/spdx.schema.json +845 -2
- package/lib/audit/index.js +25 -3
- package/lib/cli/bomAssembly.js +172 -4
- package/lib/cli/cliOptions.js +121 -17
- package/lib/cli/index.js +720 -902
- package/lib/cli/jsBom.js +156 -64
- package/lib/cli/jvmBom.js +602 -86
- package/lib/cli/managedBom.js +161 -19
- package/lib/cli/nativeBom.js +52 -5
- package/lib/core/boundedFile.js +344 -0
- package/lib/core/brotliProbe.js +182 -0
- package/lib/core/env.js +34 -0
- package/lib/core/fs.js +138 -3
- package/lib/core/globPatterns.js +218 -0
- package/lib/core/httpClient.js +98 -1
- package/lib/core/lockPaths.js +38 -0
- package/lib/core/paths.js +24 -1
- package/lib/core/processTree.js +100 -8
- package/lib/core/projectConfig.js +332 -25
- package/lib/core/toolRegistry.js +184 -0
- package/lib/ecosystems/cppEvidence.js +263 -106
- package/lib/ecosystems/cppIncludeResolver.js +16 -5
- package/lib/ecosystems/denoutils.js +2 -2
- package/lib/ecosystems/ecosystems.js +25 -10
- package/lib/ecosystems/gemHostProbe.js +301 -0
- package/lib/ecosystems/golem.js +3 -8
- package/lib/ecosystems/gradleutils.js +1909 -229
- package/lib/ecosystems/jsEvidence.js +90 -38
- package/lib/ecosystems/kosi.js +3 -5
- package/lib/ecosystems/npmVersionResolution.js +376 -0
- package/lib/ecosystems/parsers-bazel.js +107 -6
- package/lib/ecosystems/parsers-js.js +505 -22
- package/lib/ecosystems/parsers-misc.js +209 -20
- package/lib/ecosystems/parsers-python.js +178 -30
- package/lib/ecosystems/parsers-rust.js +117 -15
- package/lib/ecosystems/pythonutils.js +128 -2
- package/lib/ecosystems/remote/huggingface.js +22 -0
- package/lib/ecosystems/rubyutils.js +538 -31
- package/lib/ecosystems/rusi.js +2 -4
- package/lib/ecosystems/scalacliutils.js +2 -0
- package/lib/ecosystems/scalasem.js +798 -152
- package/lib/ecosystems/vendoredCode.js +237 -3
- package/lib/ecosystems/venvProbe.js +360 -0
- package/lib/evinser/evinser.js +536 -71
- package/lib/evinser/scalasem.js +5 -1
- package/lib/helpers/agenticToolutils.js +525 -94
- package/lib/helpers/bomSigner.js +43 -9
- package/lib/helpers/jssSigner.js +1276 -0
- package/lib/helpers/vsixutils.js +1574 -315
- package/lib/inventory/agentBlueprint.js +193 -0
- package/lib/inventory/agentToolNames.js +145 -0
- package/lib/inventory/aiCollector.js +153 -7
- package/lib/inventory/aiInventory.js +44 -8
- package/lib/inventory/aiProviders.js +324 -0
- package/lib/inventory/atomUtils.js +77 -0
- package/lib/inventory/bomUtils.js +8 -1
- package/lib/inventory/brotliDecoder.js +142 -0
- package/lib/inventory/buildToolRateLimit.js +1 -1
- package/lib/inventory/cbomutils.js +56 -7
- package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
- package/lib/inventory/citations.js +31 -2
- package/lib/inventory/communityAiConfigParser.js +978 -80
- package/lib/inventory/cyclonedx20.js +152 -0
- package/lib/inventory/cyclonedx20Common.js +286 -0
- package/lib/inventory/cyclonedx20Derived.js +159 -0
- package/lib/inventory/cyclonedx20Parties.js +552 -0
- package/lib/inventory/cyclonedx20Read.js +768 -0
- package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
- package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
- package/lib/inventory/cyclonedx20ReadContext.js +380 -0
- package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
- package/lib/inventory/cyclonedx20ReadSections.js +599 -0
- package/lib/inventory/cyclonedx20Render.js +766 -0
- package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
- package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
- package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
- package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
- package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
- package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
- package/lib/inventory/cyclonedx20RenderSections.js +499 -0
- package/lib/inventory/cyclonedx20Tables.js +594 -0
- package/lib/inventory/deps.js +141 -13
- package/lib/inventory/dosai.js +375 -6
- package/lib/inventory/dosaiParsers.js +3 -6
- package/lib/inventory/dotnetRuntime.js +367 -0
- package/lib/inventory/ecosystemFormulationParsers.js +979 -0
- package/lib/inventory/envcontext.js +436 -48
- package/lib/inventory/evidenceUtils.js +13 -1
- package/lib/inventory/fetchBatch.js +1 -1
- package/lib/inventory/formulationParsers.js +124 -14
- package/lib/inventory/gtfobins.js +13 -0
- package/lib/inventory/hbom.js +45 -6
- package/lib/inventory/hbomLoader.js +166 -0
- package/lib/inventory/hostRuntimeProbe.js +686 -0
- package/lib/inventory/jvmLocalRepos.js +9 -2
- package/lib/inventory/jvmToolEnv.js +29 -0
- package/lib/inventory/licenseEnhancer.js +12 -0
- package/lib/inventory/mavenCentralMirror.js +534 -0
- package/lib/inventory/mcpConfigParser.js +5 -0
- package/lib/inventory/nodeBuildInfo.js +218 -0
- package/lib/inventory/nodeHostProbe.js +202 -0
- package/lib/inventory/occurrenceKey.js +90 -0
- package/lib/inventory/osPackageResolver.js +182 -0
- package/lib/inventory/phpBuildInfo.js +10 -59
- package/lib/inventory/phpHostProbe.js +32 -488
- package/lib/inventory/pqcMigration.js +426 -0
- package/lib/inventory/rubyBuildInfo.js +972 -0
- package/lib/inventory/rubyHostProbe.js +218 -0
- package/lib/inventory/rustFormulationParser.js +21 -10
- package/lib/inventory/scalaCoords.js +4 -3
- package/lib/inventory/scalaDedupe.js +440 -0
- package/lib/inventory/source.js +114 -8
- package/lib/managers/binary.js +337 -3
- package/lib/managers/docker.js +79 -0
- package/lib/parsers/huggingfaceManifest.js +9 -1
- package/lib/parsers/huggingfaceUtils.js +18 -0
- package/lib/parsers/kiroPermissions.js +166 -0
- package/lib/parsers/largeJson.js +28 -11
- package/lib/parsers/vscodeExtensionId.js +183 -0
- package/lib/server/server.js +48 -35
- package/lib/stages/postgen/postgen.js +41 -1
- package/lib/stages/postgen/ruleEngine.js +13 -5
- package/lib/stages/postgen/specVersionCompat.js +76 -0
- package/lib/stages/pregen/envAudit.js +1 -0
- package/lib/stages/pregen/pregen.js +114 -57
- package/lib/validator/bomValidator.js +14 -2
- package/lib/validator/complianceEngine.js +30 -3
- package/lib/validator/complianceRules.js +1416 -4
- package/lib/validator/generated/validate-1.6.mjs +1 -1
- package/lib/validator/generated/validate-1.7.mjs +1 -1
- package/lib/validator/generated/validate-2.0.mjs +57554 -13851
- package/lib/validator/index.js +49 -8
- package/lib/validator/reporters/json.js +6 -0
- package/package.json +11 -10
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +6 -2
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +29 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +6 -0
- 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 +3 -18
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +15 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/boundedFile.d.ts +100 -0
- package/types/lib/core/boundedFile.d.ts.map +1 -0
- package/types/lib/core/brotliProbe.d.ts +37 -0
- package/types/lib/core/brotliProbe.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +14 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +4 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/globPatterns.d.ts +70 -0
- package/types/lib/core/globPatterns.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +24 -0
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/lockPaths.d.ts +19 -0
- package/types/lib/core/lockPaths.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +9 -0
- package/types/lib/core/paths.d.ts.map +1 -1
- package/types/lib/core/processTree.d.ts +17 -4
- package/types/lib/core/processTree.d.ts.map +1 -1
- package/types/lib/core/projectConfig.d.ts +47 -8
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/toolRegistry.d.ts +36 -0
- package/types/lib/core/toolRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
- package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +294 -20
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
- package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +17 -20
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +10 -0
- 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/pythonutils.d.ts +19 -1
- 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 +144 -12
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalasem.d.ts +58 -16
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
- package/types/lib/ecosystems/venvProbe.d.ts +40 -0
- package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +120 -13
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/scalasem.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +53 -19
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +20 -3
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/helpers/jssSigner.d.ts +288 -0
- package/types/lib/helpers/jssSigner.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +303 -19
- package/types/lib/helpers/vsixutils.d.ts.map +1 -1
- package/types/lib/inventory/agentBlueprint.d.ts +70 -0
- package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
- package/types/lib/inventory/agentToolNames.d.ts +51 -0
- package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/aiProviders.d.ts +85 -0
- package/types/lib/inventory/aiProviders.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +19 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/bomUtils.d.ts.map +1 -1
- package/types/lib/inventory/brotliDecoder.d.ts +58 -0
- package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +17 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -1
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
- package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +5 -0
- package/types/lib/inventory/citations.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/cyclonedx20.d.ts +99 -0
- package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
- package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
- package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
- package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
- package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
- package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
- package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
- package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
- package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
- package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
- package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
- package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
- package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
- package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
- package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
- package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
- package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
- package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +35 -2
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +36 -1
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dotnetRuntime.d.ts +91 -0
- package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
- package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +74 -12
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/gtfobins.d.ts.map +1 -1
- package/types/lib/inventory/hbom.d.ts +11 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomLoader.d.ts +54 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
- package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
- package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
- package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
- package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
- package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
- package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/occurrenceKey.d.ts +52 -0
- package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +38 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
- package/types/lib/inventory/pqcMigration.d.ts +84 -0
- package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
- package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
- package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
- package/types/lib/inventory/scalaDedupe.d.ts +43 -0
- package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +25 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/kiroPermissions.d.ts +62 -0
- package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +4 -3
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
- package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +7 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +12 -8
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts +5 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceEngine.d.ts +4 -4
- package/types/lib/validator/complianceEngine.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts +14 -2
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversions between the 1.x organizational entities and contacts and the
|
|
3
|
+
* CycloneDX 2.0 parties (#/$defs/cyclonedx-party-2.0) and common entities
|
|
4
|
+
* (#/$defs/cyclonedx-common-2.0).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
authorStringToNames,
|
|
9
|
+
clone,
|
|
10
|
+
countDrop,
|
|
11
|
+
countUnmapped,
|
|
12
|
+
identifierValues,
|
|
13
|
+
isNonEmptyString,
|
|
14
|
+
isObjectRecord,
|
|
15
|
+
} from "./cyclonedx20Common.js";
|
|
16
|
+
import { reverseAddress } from "./cyclonedx20ReadCommon.js";
|
|
17
|
+
import {
|
|
18
|
+
addLoss,
|
|
19
|
+
jsonPointer,
|
|
20
|
+
reportUnmapped,
|
|
21
|
+
reverseList,
|
|
22
|
+
reverseObject,
|
|
23
|
+
} from "./cyclonedx20ReadContext.js";
|
|
24
|
+
import {
|
|
25
|
+
PARTY_ROLE_FIELDS_1X,
|
|
26
|
+
POSTAL_ADDRESS_FIELDS,
|
|
27
|
+
} from "./cyclonedx20Tables.js";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Convert a 1.x postalAddress. Party addresses
|
|
31
|
+
* (#/$defs/cyclonedx-party-2.0/$defs/postalAddress) and common addresses
|
|
32
|
+
* (#/$defs/cyclonedx-common-2.0/$defs/postalAddress) both rename `bom-ref`
|
|
33
|
+
* to `refId`.
|
|
34
|
+
*/
|
|
35
|
+
function convertPostalAddress(address, stats) {
|
|
36
|
+
if (!isObjectRecord(address)) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const converted = {};
|
|
40
|
+
const refId = address.refId ?? address["bom-ref"];
|
|
41
|
+
if (isNonEmptyString(refId)) {
|
|
42
|
+
converted.refId = refId;
|
|
43
|
+
}
|
|
44
|
+
for (const field of POSTAL_ADDRESS_FIELDS) {
|
|
45
|
+
if (typeof address[field] === "string") {
|
|
46
|
+
converted[field] = address[field];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
countUnmapped(
|
|
50
|
+
stats,
|
|
51
|
+
"address",
|
|
52
|
+
address,
|
|
53
|
+
new Set([...POSTAL_ADDRESS_FIELDS, "bom-ref", "refId"]),
|
|
54
|
+
);
|
|
55
|
+
return Object.keys(converted).length ? converted : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Convert a 1.x organizationalContact to a 2.0 party `person`
|
|
60
|
+
* (#/$defs/cyclonedx-party-2.0/$defs/person: `email` and `phone` are arrays of
|
|
61
|
+
* `{address}` / `{number}` objects, and there is no `bom-ref`).
|
|
62
|
+
*/
|
|
63
|
+
function contactToPerson(contact, stats) {
|
|
64
|
+
if (isNonEmptyString(contact)) {
|
|
65
|
+
return { name: contact };
|
|
66
|
+
}
|
|
67
|
+
if (!isObjectRecord(contact)) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const person = {};
|
|
71
|
+
if (isNonEmptyString(contact.name)) {
|
|
72
|
+
person.name = contact.name;
|
|
73
|
+
}
|
|
74
|
+
if (isNonEmptyString(contact.email)) {
|
|
75
|
+
person.email = [{ address: contact.email }];
|
|
76
|
+
}
|
|
77
|
+
if (isNonEmptyString(contact.phone)) {
|
|
78
|
+
person.phone = [{ number: contact.phone }];
|
|
79
|
+
}
|
|
80
|
+
countUnmapped(
|
|
81
|
+
stats,
|
|
82
|
+
"party.person",
|
|
83
|
+
contact,
|
|
84
|
+
new Set(["name", "email", "phone", "bom-ref"]),
|
|
85
|
+
);
|
|
86
|
+
return Object.keys(person).length ? person : undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A person party playing `role` for a 1.x contact. The contact's `bom-ref`
|
|
91
|
+
* is the party's refId (#/$defs/cyclonedx-party-2.0/$defs/party).
|
|
92
|
+
*
|
|
93
|
+
* @param {object|string} contact 1.x organizationalContact
|
|
94
|
+
* @param {string} role Predefined role
|
|
95
|
+
* @param {object} stats Render counters
|
|
96
|
+
* @returns {object|undefined} 2.0 party
|
|
97
|
+
*/
|
|
98
|
+
export function contactToParty(contact, role, stats) {
|
|
99
|
+
const person = contactToPerson(contact, stats);
|
|
100
|
+
if (!person) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const party = {};
|
|
104
|
+
if (isNonEmptyString(contact?.["bom-ref"])) {
|
|
105
|
+
party.refId = contact["bom-ref"];
|
|
106
|
+
}
|
|
107
|
+
party.roles = [{ role }];
|
|
108
|
+
party.person = person;
|
|
109
|
+
return party;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Convert a 1.x organizationalEntity into 2.0 parties playing `role`
|
|
114
|
+
* (#/$defs/cyclonedx-party-2.0/$defs/party, required `[roles]`, exactly one
|
|
115
|
+
* identity sub-shape). The organization
|
|
116
|
+
* (#/$defs/cyclonedx-party-2.0/$defs/organization) takes `url` as
|
|
117
|
+
* `[{url}]` and `addresses` as an array and has no `bom-ref` or `contact`, so
|
|
118
|
+
* every 1.x contact becomes its own person party with the same role.
|
|
119
|
+
*/
|
|
120
|
+
export function entityToParties(entity, role, stats) {
|
|
121
|
+
if (!isObjectRecord(entity)) {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
const organization = {};
|
|
125
|
+
if (isNonEmptyString(entity.name)) {
|
|
126
|
+
organization.name = entity.name;
|
|
127
|
+
}
|
|
128
|
+
// A 2.0-shaped organization read back from a 2.0 document already has
|
|
129
|
+
// `{url}` objects and `addresses`; both shapes are accepted.
|
|
130
|
+
const urls = identifierValues(entity.url)
|
|
131
|
+
.map((url) =>
|
|
132
|
+
isNonEmptyString(url)
|
|
133
|
+
? { url }
|
|
134
|
+
: isNonEmptyString(url?.url)
|
|
135
|
+
? clone(url)
|
|
136
|
+
: undefined,
|
|
137
|
+
)
|
|
138
|
+
.filter(Boolean);
|
|
139
|
+
if (urls.length) {
|
|
140
|
+
organization.url = urls;
|
|
141
|
+
}
|
|
142
|
+
const addresses = [
|
|
143
|
+
entity.address,
|
|
144
|
+
...(Array.isArray(entity.addresses) ? entity.addresses : []),
|
|
145
|
+
]
|
|
146
|
+
.map((address) => convertPostalAddress(address, stats))
|
|
147
|
+
.filter(Boolean);
|
|
148
|
+
if (addresses.length) {
|
|
149
|
+
organization.addresses = addresses;
|
|
150
|
+
}
|
|
151
|
+
countUnmapped(
|
|
152
|
+
stats,
|
|
153
|
+
"party.organization",
|
|
154
|
+
entity,
|
|
155
|
+
new Set(["name", "url", "address", "addresses", "contact", "bom-ref"]),
|
|
156
|
+
);
|
|
157
|
+
const parties = [];
|
|
158
|
+
if (Object.keys(organization).length) {
|
|
159
|
+
// The entity's bom-ref identifies the organization party.
|
|
160
|
+
parties.push(
|
|
161
|
+
isNonEmptyString(entity["bom-ref"])
|
|
162
|
+
? { refId: entity["bom-ref"], roles: [{ role }], organization }
|
|
163
|
+
: { roles: [{ role }], organization },
|
|
164
|
+
);
|
|
165
|
+
} else if (entity["bom-ref"] !== undefined) {
|
|
166
|
+
countDrop(stats, "party.organization.bom-ref");
|
|
167
|
+
}
|
|
168
|
+
for (const contact of Array.isArray(entity.contact) ? entity.contact : []) {
|
|
169
|
+
const party = contactToParty(contact, role, stats);
|
|
170
|
+
if (party) {
|
|
171
|
+
parties.push(party);
|
|
172
|
+
} else {
|
|
173
|
+
countDrop(stats, "party.contact (empty)");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!parties.length) {
|
|
177
|
+
countDrop(stats, "party.organization (empty)");
|
|
178
|
+
}
|
|
179
|
+
return parties;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Convert a 1.x organizationalContact to the 2.0 common organizationalContact
|
|
184
|
+
* (#/$defs/cyclonedx-common-2.0/$defs/organizationalContact), which renames
|
|
185
|
+
* `bom-ref` to `refId`. Used by metadata authors and annotators.
|
|
186
|
+
*/
|
|
187
|
+
export function toCommonContact(contact, stats) {
|
|
188
|
+
if (isNonEmptyString(contact)) {
|
|
189
|
+
return { name: contact };
|
|
190
|
+
}
|
|
191
|
+
if (!isObjectRecord(contact)) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
const converted = {};
|
|
195
|
+
const refId = contact.refId ?? contact["bom-ref"];
|
|
196
|
+
if (isNonEmptyString(refId)) {
|
|
197
|
+
converted.refId = refId;
|
|
198
|
+
}
|
|
199
|
+
for (const field of ["name", "email", "phone"]) {
|
|
200
|
+
if (isNonEmptyString(contact[field])) {
|
|
201
|
+
converted[field] = contact[field];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
countUnmapped(
|
|
205
|
+
stats,
|
|
206
|
+
"contact",
|
|
207
|
+
contact,
|
|
208
|
+
new Set(["name", "email", "phone", "bom-ref", "refId"]),
|
|
209
|
+
);
|
|
210
|
+
return Object.keys(converted).length ? converted : undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Convert a 1.x organizationalEntity to the 2.0 common organizationalEntity
|
|
215
|
+
* (#/$defs/cyclonedx-common-2.0/$defs/organizationalEntity), used by
|
|
216
|
+
* metadata.supplier, metadata.manufacturer and annotator.organization. It
|
|
217
|
+
* keeps `url` strings and `contact`, and renames `bom-ref` to `refId`.
|
|
218
|
+
*/
|
|
219
|
+
export function toCommonEntity(entity, stats) {
|
|
220
|
+
if (!isObjectRecord(entity)) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
const converted = {};
|
|
224
|
+
const refId = entity.refId ?? entity["bom-ref"];
|
|
225
|
+
if (isNonEmptyString(refId)) {
|
|
226
|
+
converted.refId = refId;
|
|
227
|
+
}
|
|
228
|
+
if (typeof entity.name === "string") {
|
|
229
|
+
converted.name = entity.name;
|
|
230
|
+
}
|
|
231
|
+
const address = convertPostalAddress(entity.address, stats);
|
|
232
|
+
if (address) {
|
|
233
|
+
converted.address = address;
|
|
234
|
+
}
|
|
235
|
+
const urls = identifierValues(entity.url).filter(isNonEmptyString);
|
|
236
|
+
if (urls.length) {
|
|
237
|
+
converted.url = urls;
|
|
238
|
+
}
|
|
239
|
+
const contacts = (Array.isArray(entity.contact) ? entity.contact : [])
|
|
240
|
+
.map((contact) => toCommonContact(contact, stats))
|
|
241
|
+
.filter(Boolean);
|
|
242
|
+
if (contacts.length) {
|
|
243
|
+
converted.contact = contacts;
|
|
244
|
+
}
|
|
245
|
+
countUnmapped(
|
|
246
|
+
stats,
|
|
247
|
+
"organization",
|
|
248
|
+
entity,
|
|
249
|
+
new Set(["name", "url", "address", "contact", "bom-ref", "refId"]),
|
|
250
|
+
);
|
|
251
|
+
return converted;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Convert the 1.x party-ish component fields into `parties`
|
|
256
|
+
* (#/$defs/cyclonedx-party-2.0/$defs/party). `author` strings and `authors`
|
|
257
|
+
* contacts become persons with the `author` role, `publisher` an organization
|
|
258
|
+
* with the `publisher` role, and supplier/manufacturer organizations keep
|
|
259
|
+
* their roles.
|
|
260
|
+
*/
|
|
261
|
+
export function collectParties(component, stats) {
|
|
262
|
+
const parties = [];
|
|
263
|
+
for (const name of authorStringToNames(component.author)) {
|
|
264
|
+
parties.push({ roles: [{ role: "author" }], person: { name } });
|
|
265
|
+
}
|
|
266
|
+
for (const contact of Array.isArray(component.authors)
|
|
267
|
+
? component.authors
|
|
268
|
+
: []) {
|
|
269
|
+
const party = contactToParty(contact, "author", stats);
|
|
270
|
+
if (party) {
|
|
271
|
+
parties.push(party);
|
|
272
|
+
} else {
|
|
273
|
+
countDrop(stats, "component.authors (empty)");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (isNonEmptyString(component.publisher)) {
|
|
277
|
+
parties.push({
|
|
278
|
+
roles: [{ role: "publisher" }],
|
|
279
|
+
organization: { name: component.publisher },
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
parties.push(...entityToParties(component.supplier, "supplier", stats));
|
|
283
|
+
parties.push(
|
|
284
|
+
...entityToParties(component.manufacturer, "manufacturer", stats),
|
|
285
|
+
);
|
|
286
|
+
return parties;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
// Reverse: 2.0 parties back to the 1.x supplier, manufacturer, authors,
|
|
291
|
+
// publisher and provider fields.
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
|
|
294
|
+
/** organization url entries `{name?, url}` back to 1.x url strings. */
|
|
295
|
+
function reverseOrganizationUrls(ctx, value, pointer) {
|
|
296
|
+
return reverseList(ctx, value, pointer, (_ctx, entry, entryPointer) => {
|
|
297
|
+
if (isNonEmptyString(entry)) {
|
|
298
|
+
return entry;
|
|
299
|
+
}
|
|
300
|
+
if (!isObjectRecord(entry) || !isNonEmptyString(entry.url)) {
|
|
301
|
+
addLoss(ctx, entryPointer, "organization url has no url");
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
reportUnmapped(ctx, "organization.url", entry, entryPointer, URL_KEYS);
|
|
305
|
+
return entry.url;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
const URL_KEYS = Object.freeze(new Set(["url"]));
|
|
309
|
+
|
|
310
|
+
/** The first entry of a 2.0 list as one 1.x value; the rest are losses. */
|
|
311
|
+
function firstOfList(kind, convertEntry) {
|
|
312
|
+
return (ctx, value, pointer) => {
|
|
313
|
+
const converted = reverseList(ctx, value, pointer, convertEntry);
|
|
314
|
+
if (converted && converted.length > 1) {
|
|
315
|
+
for (let index = 1; index < converted.length; index++) {
|
|
316
|
+
addLoss(
|
|
317
|
+
ctx,
|
|
318
|
+
jsonPointer(pointer, index),
|
|
319
|
+
`${kind}: 1.x holds one value; only the first is kept`,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return converted?.[0];
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const ORGANIZATION_SPEC = Object.freeze({
|
|
328
|
+
name: true,
|
|
329
|
+
url: Object.freeze({ convert: reverseOrganizationUrls }),
|
|
330
|
+
addresses: Object.freeze({
|
|
331
|
+
to: "address",
|
|
332
|
+
convert: firstOfList("organization.addresses", reverseAddress),
|
|
333
|
+
}),
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const EMAIL_KEYS = Object.freeze(new Set(["address"]));
|
|
337
|
+
const PHONE_KEYS = Object.freeze(new Set(["number"]));
|
|
338
|
+
|
|
339
|
+
/** A person's `[{name?, address}]` / `[{name?, number}]` list → one string. */
|
|
340
|
+
function contactValue(member, keys) {
|
|
341
|
+
return firstOfList(`person.${member}`, (ctx, entry, pointer) => {
|
|
342
|
+
const field = member === "email" ? "address" : "number";
|
|
343
|
+
if (!isObjectRecord(entry) || !isNonEmptyString(entry[field])) {
|
|
344
|
+
addLoss(ctx, pointer, `person.${member} entry has no ${field}`);
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
reportUnmapped(ctx, `person.${member}`, entry, pointer, keys);
|
|
348
|
+
return entry[field];
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const PERSON_SPEC = Object.freeze({
|
|
353
|
+
name: true,
|
|
354
|
+
email: Object.freeze({ convert: contactValue("email", EMAIL_KEYS) }),
|
|
355
|
+
phone: Object.freeze({ convert: contactValue("phone", PHONE_KEYS) }),
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const PARTY_KEYS = Object.freeze(
|
|
359
|
+
new Set(["refId", "roles", "organization", "person"]),
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
/** Resolve a partyReference (`{ref}`) against definitions.parties. */
|
|
363
|
+
function resolveParty(ctx, entry, pointer) {
|
|
364
|
+
if (!isObjectRecord(entry)) {
|
|
365
|
+
addLoss(ctx, pointer, "party is not an object");
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
if (typeof entry.ref !== "string") {
|
|
369
|
+
return { party: entry, pointer };
|
|
370
|
+
}
|
|
371
|
+
const declared = ctx.partyIndex.get(entry.ref);
|
|
372
|
+
if (!declared) {
|
|
373
|
+
addLoss(
|
|
374
|
+
ctx,
|
|
375
|
+
jsonPointer(pointer, "ref"),
|
|
376
|
+
`party reference '${entry.ref}' could not be resolved`,
|
|
377
|
+
);
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
return { party: declared.entry, pointer: declared.pointer };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** The predefined roles of a party that `roleFields` maps to 1.x fields. */
|
|
384
|
+
function mappedRoles(ctx, party, pointer, roleFields) {
|
|
385
|
+
const roles = [];
|
|
386
|
+
(Array.isArray(party.roles) ? party.roles : []).forEach((role, index) => {
|
|
387
|
+
const rolePointer = jsonPointer(pointer, "roles", index);
|
|
388
|
+
if (!isObjectRecord(role) || typeof role.role !== "string") {
|
|
389
|
+
addLoss(ctx, rolePointer, "custom party role has no 1.x field");
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (role.order !== undefined) {
|
|
393
|
+
addLoss(
|
|
394
|
+
ctx,
|
|
395
|
+
jsonPointer(rolePointer, "order"),
|
|
396
|
+
"role.order has no 1.x field",
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (!Object.hasOwn(roleFields, role.role)) {
|
|
400
|
+
addLoss(ctx, rolePointer, `party role '${role.role}' has no 1.x field`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
roles.push(role.role);
|
|
404
|
+
});
|
|
405
|
+
if (roles.length > 1) {
|
|
406
|
+
addLoss(
|
|
407
|
+
ctx,
|
|
408
|
+
jsonPointer(pointer, "roles"),
|
|
409
|
+
"a party with several roles becomes one 1.x entry per role",
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
return roles;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** The 1.x organization or contact of one party, or undefined. */
|
|
416
|
+
function partyIdentity(ctx, party, pointer) {
|
|
417
|
+
reportUnmapped(ctx, "party", party, pointer, PARTY_KEYS);
|
|
418
|
+
let identity;
|
|
419
|
+
let kind;
|
|
420
|
+
if (isObjectRecord(party.organization)) {
|
|
421
|
+
kind = "organization";
|
|
422
|
+
identity = reverseObject(
|
|
423
|
+
ctx,
|
|
424
|
+
"organization",
|
|
425
|
+
party.organization,
|
|
426
|
+
jsonPointer(pointer, "organization"),
|
|
427
|
+
ORGANIZATION_SPEC,
|
|
428
|
+
);
|
|
429
|
+
} else if (isObjectRecord(party.person)) {
|
|
430
|
+
kind = "person";
|
|
431
|
+
identity = reverseObject(
|
|
432
|
+
ctx,
|
|
433
|
+
"person",
|
|
434
|
+
party.person,
|
|
435
|
+
jsonPointer(pointer, "person"),
|
|
436
|
+
PERSON_SPEC,
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (!identity) {
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
if (isNonEmptyString(party.refId)) {
|
|
443
|
+
identity = { "bom-ref": party.refId, ...identity };
|
|
444
|
+
}
|
|
445
|
+
return { kind, identity };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Put one party identity into the 1.x field for `role`. */
|
|
449
|
+
function assignPartyRole(ctx, fields, role, entry, pointer) {
|
|
450
|
+
const { kind, identity } = entry;
|
|
451
|
+
const field = PARTY_ROLE_FIELDS_1X[role];
|
|
452
|
+
if (field === "authors") {
|
|
453
|
+
if (kind === "person") {
|
|
454
|
+
(fields.authors ||= []).push(identity);
|
|
455
|
+
} else {
|
|
456
|
+
addLoss(ctx, pointer, "an organization author has no 1.x field");
|
|
457
|
+
}
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (field === "publisher") {
|
|
461
|
+
if (fields.publisher !== undefined || !isNonEmptyString(identity.name)) {
|
|
462
|
+
addLoss(ctx, pointer, "publisher: 1.x holds one name");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
fields.publisher = identity.name;
|
|
466
|
+
const extra = Object.keys(identity).filter((key) => key !== "name");
|
|
467
|
+
if (extra.length) {
|
|
468
|
+
addLoss(
|
|
469
|
+
ctx,
|
|
470
|
+
pointer,
|
|
471
|
+
`publisher keeps only the name (${extra.join(", ")})`,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
if (kind === "person") {
|
|
475
|
+
addLoss(ctx, pointer, "a person publisher is written as a name");
|
|
476
|
+
}
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
const entity = (fields[field] ||= {});
|
|
480
|
+
if (kind === "person") {
|
|
481
|
+
(entity.contact ||= []).push(identity);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (entity.name !== undefined || entity.url !== undefined) {
|
|
485
|
+
addLoss(ctx, pointer, `${field}: 1.x holds one organization`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const contact = entity.contact;
|
|
489
|
+
Object.assign(entity, identity);
|
|
490
|
+
if (contact) {
|
|
491
|
+
delete entity.contact;
|
|
492
|
+
entity.contact = contact;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Read 2.0 component or service `parties` into the 1.x fields
|
|
498
|
+
* (`supplier`, `manufacturer`, `authors`, `publisher`, `provider`). A person
|
|
499
|
+
* playing the supplier, manufacturer or provider role becomes a contact of
|
|
500
|
+
* that organization, the inverse of entityToParties. Party references resolve
|
|
501
|
+
* against definitions.parties. Everything else is a loss.
|
|
502
|
+
*
|
|
503
|
+
* @param {object} ctx Reader context
|
|
504
|
+
* @param {Array} parties 2.0 parties
|
|
505
|
+
* @param {string} pointer JSON pointer of `parties`
|
|
506
|
+
* @param {object} roleFields Roles to read (subset of PARTY_ROLE_FIELDS_1X)
|
|
507
|
+
* @returns {object} 1.x fields by name
|
|
508
|
+
*/
|
|
509
|
+
export function reverseParties(ctx, parties, pointer, roleFields) {
|
|
510
|
+
const fields = {};
|
|
511
|
+
if (!Array.isArray(parties)) {
|
|
512
|
+
addLoss(ctx, pointer, "expected an array");
|
|
513
|
+
return fields;
|
|
514
|
+
}
|
|
515
|
+
parties.forEach((entry, index) => {
|
|
516
|
+
const read = readParty(ctx, entry, jsonPointer(pointer, index), roleFields);
|
|
517
|
+
for (const role of read?.roles || []) {
|
|
518
|
+
assignPartyRole(
|
|
519
|
+
ctx,
|
|
520
|
+
fields,
|
|
521
|
+
role,
|
|
522
|
+
structuredClone(read.identity),
|
|
523
|
+
read.pointer,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
return fields;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Read one 2.0 party (inline or a partyReference) whose roles `roleFields`
|
|
532
|
+
* lists: its roles, the 1.x organization or contact it describes, and the
|
|
533
|
+
* pointer of the party object. Unlisted roles and members are losses.
|
|
534
|
+
*
|
|
535
|
+
* @param {object} ctx Reader context
|
|
536
|
+
* @param {object} entry 2.0 party or partyReference
|
|
537
|
+
* @param {string} pointer JSON pointer of `entry`
|
|
538
|
+
* @param {object} roleFields Role names to read, as keys
|
|
539
|
+
* @returns {{roles: string[], identity: {kind: string, identity: object}, pointer: string}|undefined}
|
|
540
|
+
*/
|
|
541
|
+
export function readParty(ctx, entry, pointer, roleFields) {
|
|
542
|
+
const resolved = resolveParty(ctx, entry, pointer);
|
|
543
|
+
if (!resolved) {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
const roles = mappedRoles(ctx, resolved.party, resolved.pointer, roleFields);
|
|
547
|
+
if (!roles.length) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
const identity = partyIdentity(ctx, resolved.party, resolved.pointer);
|
|
551
|
+
return identity ? { roles, identity, pointer: resolved.pointer } : undefined;
|
|
552
|
+
}
|