@@ -17,39 +17,31 @@ SPDX-License-Identifier: Apache-2.0
1717Copyright (c) OWASP Foundation. All Rights Reserved.
1818*/
1919
20- import { dirname } from 'node:path'
21-
22- import * as CDX from '@cyclonedx/cyclonedx-library'
20+ import type * as CDX from '@cyclonedx/cyclonedx-library'
2321import type { Compilation , Module } from 'webpack'
2422
23+ import type {
24+ PackageDescription } from './_helpers'
2525import {
2626 getPackageDescription ,
27- isNonNullable ,
28- normalizePackageManifest ,
29- type PackageDescription ,
30- structuredClonePolyfill } from './_helpers'
27+ isNonNullable } from './_helpers'
28+ import type { RichComponentBuilder } from './richComponentBuilder'
3129
3230type WebpackLogger = Compilation [ 'logger' ]
3331
3432export class Extractor {
3533 readonly #compilation: Compilation
36- readonly #componentBuilder: CDX . Builders . FromNodePackageJson . ComponentBuilder
37- readonly #purlFactory: CDX . Factories . FromNodePackageJson . PackageUrlFactory
38- readonly #leGatherer: CDX . Utils . LicenseUtility . LicenseEvidenceGatherer
34+ readonly #componentBuilder: RichComponentBuilder
3935
4036 constructor (
4137 compilation : Compilation ,
42- componentBuilder : CDX . Builders . FromNodePackageJson . ComponentBuilder ,
43- purlFactory : CDX . Factories . FromNodePackageJson . PackageUrlFactory ,
44- leFetcher : CDX . Utils . LicenseUtility . LicenseEvidenceGatherer
38+ componentBuilder : RichComponentBuilder ,
4539 ) {
4640 this . #compilation = compilation
4741 this . #componentBuilder = componentBuilder
48- this . #purlFactory = purlFactory
49- this . #leGatherer = leFetcher
5042 }
5143
52- generateComponents ( modules : Iterable < Module > , collectEvidence : boolean , logger ?: WebpackLogger ) : Iterable < CDX . Models . Component > {
44+ generateComponents ( modules : Iterable < Module > , componentSubstitutionMap : Map < string , CDX . Models . Component > , collectEvidence : boolean , logger ?: WebpackLogger ) : Iterable < CDX . Models . Component > {
5345 const pkgs : Record < string , CDX . Models . Component | undefined > = { }
5446 const components = new Map < Module , CDX . Models . Component > ( )
5547
@@ -68,7 +60,7 @@ export class Extractor {
6860 if ( component === undefined ) {
6961 logger ?. log ( 'try to build new Component from PkgPath:' , pkg . path )
7062 try {
71- component = this . makeComponent ( pkg , collectEvidence , logger )
63+ component = this . # makeComponent( pkg , componentSubstitutionMap , collectEvidence , logger )
7264 } catch ( err ) {
7365 logger ?. debug ( 'unexpected error:' , err )
7466 logger ?. warn ( 'skipped Component from PkgPath' , pkg . path )
@@ -90,39 +82,21 @@ export class Extractor {
9082 /**
9183 * @throws {@link Error } when no component could be fetched
9284 */
93- makeComponent ( pkg : PackageDescription , collectEvidence : boolean , logger ?: WebpackLogger ) : CDX . Models . Component {
94- try {
95- // work with a deep copy, because `normalizePackageManifest()` might modify the data
96- /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- ach */
97- const _packageJson = structuredClonePolyfill ( pkg . packageJson )
98- normalizePackageManifest ( _packageJson )
99- pkg . packageJson = _packageJson
100- } catch ( e ) {
101- logger ?. warn ( 'normalizePackageJson from PkgPath' , pkg . path , 'failed:' , e )
102- }
103-
104- const component = this . #componentBuilder. makeComponent (
105- /* @ts -expect-error TS2559 */
106- pkg . packageJson as PackageDescription ) /* eslint-disable-line @typescript-eslint/no-unsafe-type-assertion -- ack */
107-
108- if ( component === undefined ) {
109- throw new Error ( `failed building Component from PkgPath ${ pkg . path } ` )
85+ #makeComponent( pkg : PackageDescription , componentSubstitutionMap : Map < string , CDX . Models . Component > , collectEvidence : boolean , logger ?: WebpackLogger ) : CDX . Models . Component
86+ {
87+ const newComponent = this . #componentBuilder. makeComponent ( pkg , collectEvidence , logger )
88+ if ( newComponent === undefined ) {
89+ throw Error ( `failed building Component from PkgPath ${ pkg . path } ` )
11090 }
11191
112- component . licenses . forEach ( l => {
113- l . acknowledgement = CDX . Enums . LicenseAcknowledgement . Declared
114- } )
115-
116- if ( collectEvidence ) {
117- component . evidence = new CDX . Models . ComponentEvidence ( {
118- licenses : new CDX . Models . LicenseRepository ( this . getLicenseEvidence ( dirname ( pkg . path ) , logger ) )
119- } )
92+ if ( newComponent . bomRef . value !== undefined ) {
93+ const remappedComponent = componentSubstitutionMap . get ( newComponent . bomRef . value )
94+ if ( remappedComponent !== undefined ) {
95+ return remappedComponent
96+ }
12097 }
12198
122- component . purl = this . #purlFactory. makeFromComponent ( component )
123- component . bomRef . value = component . purl ?. toString ( )
124-
125- return component
99+ return newComponent
126100 }
127101
128102 #linkDependencies ( modulesComponents : Map < Module , CDX . Models . Component > ) : void {
@@ -135,25 +109,4 @@ export class Extractor {
135109 }
136110 }
137111 }
138-
139- public * getLicenseEvidence ( packageDir : string , logger ?: WebpackLogger ) : Generator < CDX . Models . License > {
140- const files = this . #leGatherer. getFileAttachments (
141- packageDir ,
142- ( error : Error ) : void => {
143- /* c8 ignore next 2 */
144- logger ?. info ( error . message )
145- logger ?. debug ( error . message , error )
146- }
147- )
148- try {
149- for ( const { file, text} of files ) {
150- yield new CDX . Models . NamedLicense ( `file: ${ file } ` , { text } )
151- }
152- }
153- /* c8 ignore next 3 */
154- catch ( e ) {
155- // generator will not throw before first `.nest()` is called ...
156- logger ?. warn ( 'collecting license evidence in' , packageDir , 'failed:' , e )
157- }
158- }
159112}
0 commit comments