@cyclonedx/cyclonedx-library 1.2.0 → 1.3.2
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 +3 -2
- package/dist.node/builders/fromNodePackageJson.node.js.map +1 -1
- package/dist.node/factories/license.js +2 -2
- package/dist.node/factories/license.js.map +1 -1
- package/dist.node/factories/packageUrl.js.map +1 -1
- package/dist.node/models/attachment.js.map +1 -1
- package/dist.node/models/bomRef.js +1 -1
- package/dist.node/models/bomRef.js.map +1 -1
- package/dist.node/models/component.js +2 -0
- package/dist.node/models/component.js.map +1 -1
- package/dist.node/models/externalReference.js.map +1 -1
- package/dist.node/models/index.js +1 -0
- package/dist.node/models/index.js.map +1 -1
- package/dist.node/models/license.js.map +1 -1
- package/dist.node/models/property.js +37 -0
- package/dist.node/models/property.js.map +1 -0
- package/dist.node/models/swid.js.map +1 -1
- package/dist.node/serialize/baseSerializer.js +8 -3
- package/dist.node/serialize/baseSerializer.js.map +1 -1
- package/dist.node/serialize/json/normalize.js +21 -1
- package/dist.node/serialize/json/normalize.js.map +1 -1
- package/dist.node/serialize/jsonSerializer.js.map +1 -1
- package/dist.node/serialize/xml/normalize.js +30 -1
- package/dist.node/serialize/xml/normalize.js.map +1 -1
- package/dist.node/serialize/xmlBaseSerializer.js.map +1 -1
- package/dist.node/spec.js +11 -6
- package/dist.node/spec.js.map +1 -1
- package/dist.web/lib.dev.js +123 -15
- package/dist.web/lib.dev.js.map +1 -1
- package/dist.web/lib.js +1 -1
- package/package.json +2 -2
- package/res/README.md +2 -2
- package/res/bom-1.4.SNAPSHOT.schema.json +1 -1
- package/res/bom-1.4.SNAPSHOT.xsd +12 -2
- package/res/spdx.SNAPSHOT.schema.json +487 -482
- package/res/spdx.SNAPSHOT.xsd +1069 -1044
- package/src/builders/fromNodePackageJson.node.ts +3 -3
- package/src/factories/license.ts +2 -2
- package/src/factories/packageUrl.ts +1 -1
- package/src/models/attachment.ts +1 -1
- package/src/models/bom.ts +1 -1
- package/src/models/bomRef.ts +2 -2
- package/src/models/component.ts +5 -1
- package/src/models/externalReference.ts +1 -1
- package/src/models/index.ts +1 -0
- package/src/models/license.ts +3 -3
- package/src/models/property.ts +42 -0
- package/src/models/swid.ts +1 -1
- package/src/serialize/baseSerializer.ts +11 -4
- package/src/serialize/json/normalize.ts +32 -5
- package/src/serialize/json/types.ts +6 -0
- package/src/serialize/jsonSerializer.ts +1 -1
- package/src/serialize/xml/normalize.ts +41 -5
- package/src/serialize/xmlBaseSerializer.ts +1 -1
- package/src/spec.ts +28 -22
|
@@ -29,7 +29,7 @@ import { PackageJson, splitNameGroup } from '../helpers/packageJson'
|
|
|
29
29
|
export class ToolBuilder {
|
|
30
30
|
readonly #extRefFactory: Factories.FromNodePackageJson.ExternalReferenceFactory
|
|
31
31
|
|
|
32
|
-
constructor (extRefFactory:
|
|
32
|
+
constructor (extRefFactory: ToolBuilder['extRefFactory']) {
|
|
33
33
|
this.#extRefFactory = extRefFactory
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -58,8 +58,8 @@ export class ComponentBuilder {
|
|
|
58
58
|
readonly #licenseFactory: Factories.LicenseFactory
|
|
59
59
|
|
|
60
60
|
constructor (
|
|
61
|
-
extRefFactory:
|
|
62
|
-
licenseFactory:
|
|
61
|
+
extRefFactory: ComponentBuilder['extRefFactory'],
|
|
62
|
+
licenseFactory: ComponentBuilder['licenseFactory']
|
|
63
63
|
) {
|
|
64
64
|
this.#extRefFactory = extRefFactory
|
|
65
65
|
this.#licenseFactory = licenseFactory
|
package/src/factories/license.ts
CHANGED
|
@@ -24,7 +24,7 @@ export class LicenseFactory {
|
|
|
24
24
|
makeFromString (value: string): License {
|
|
25
25
|
try {
|
|
26
26
|
return this.makeExpression(value)
|
|
27
|
-
} catch
|
|
27
|
+
} catch {
|
|
28
28
|
return this.makeDisjunctive(value)
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -39,7 +39,7 @@ export class LicenseFactory {
|
|
|
39
39
|
makeDisjunctive (value: string): DisjunctiveLicense {
|
|
40
40
|
try {
|
|
41
41
|
return this.makeDisjunctiveWithId(value)
|
|
42
|
-
} catch
|
|
42
|
+
} catch {
|
|
43
43
|
return this.makeDisjunctiveWithName(value)
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/models/attachment.ts
CHANGED
|
@@ -29,7 +29,7 @@ export class Attachment {
|
|
|
29
29
|
content: string
|
|
30
30
|
encoding?: AttachmentEncoding
|
|
31
31
|
|
|
32
|
-
constructor (content:
|
|
32
|
+
constructor (content: Attachment['content'], op: OptionalProperties = {}) {
|
|
33
33
|
this.contentType = op.contentType
|
|
34
34
|
this.content = content
|
|
35
35
|
this.encoding = op.encoding
|
package/src/models/bom.ts
CHANGED
|
@@ -45,7 +45,7 @@ export class Bom {
|
|
|
45
45
|
// The dependency graph can be normalized on render-time, no need to store it in the bom model.
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* @throws {TypeError} if {@see op.version} is
|
|
48
|
+
* @throws {TypeError} if {@see op.version} is neither {@see PositiveInteger} nor {@see undefined}
|
|
49
49
|
* @throws {TypeError} if {@see op.serialNumber} is neither {@see UrnUuid} nor {@see undefined}
|
|
50
50
|
*/
|
|
51
51
|
constructor (op: OptionalProperties = {}) {
|
package/src/models/bomRef.ts
CHANGED
|
@@ -24,12 +24,12 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
|
|
|
24
24
|
export class BomRef {
|
|
25
25
|
value?: string
|
|
26
26
|
|
|
27
|
-
constructor (value?:
|
|
27
|
+
constructor (value?: BomRef['value']) {
|
|
28
28
|
this.value = value
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
compare (other: BomRef): number {
|
|
32
|
-
return
|
|
32
|
+
return this.toString().localeCompare(other.toString())
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
toString (): string {
|
package/src/models/component.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { OrganizationalEntity } from './organizationalEntity'
|
|
|
27
27
|
import { ExternalReferenceRepository } from './externalReference'
|
|
28
28
|
import { LicenseRepository } from './license'
|
|
29
29
|
import { SWID } from './swid'
|
|
30
|
+
import { PropertyRepository } from './property'
|
|
30
31
|
import { Comparable, SortableSet } from '../helpers/sortableSet'
|
|
31
32
|
import { treeIterator } from '../helpers/tree'
|
|
32
33
|
|
|
@@ -48,6 +49,7 @@ interface OptionalProperties {
|
|
|
48
49
|
dependencies?: Component['dependencies']
|
|
49
50
|
components?: Component['components']
|
|
50
51
|
cpe?: Component['cpe']
|
|
52
|
+
properties?: Component['properties']
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export class Component implements Comparable {
|
|
@@ -68,6 +70,7 @@ export class Component implements Comparable {
|
|
|
68
70
|
version?: string
|
|
69
71
|
dependencies: BomRefRepository
|
|
70
72
|
components: ComponentRepository
|
|
73
|
+
properties: PropertyRepository
|
|
71
74
|
|
|
72
75
|
/** @see bomRef */
|
|
73
76
|
readonly #bomRef: BomRef
|
|
@@ -78,7 +81,7 @@ export class Component implements Comparable {
|
|
|
78
81
|
/**
|
|
79
82
|
* @throws {TypeError} if {@see op.cpe} is neither {@see CPE} nor {@see undefined}
|
|
80
83
|
*/
|
|
81
|
-
constructor (type:
|
|
84
|
+
constructor (type: Component['type'], name: Component['name'], op: OptionalProperties = {}) {
|
|
82
85
|
this.#bomRef = new BomRef(op.bomRef)
|
|
83
86
|
this.type = type
|
|
84
87
|
this.name = name
|
|
@@ -98,6 +101,7 @@ export class Component implements Comparable {
|
|
|
98
101
|
this.dependencies = op.dependencies ?? new BomRefRepository()
|
|
99
102
|
this.components = op.components ?? new ComponentRepository()
|
|
100
103
|
this.cpe = op.cpe
|
|
104
|
+
this.properties = op.properties ?? new PropertyRepository()
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
get bomRef (): BomRef {
|
|
@@ -29,7 +29,7 @@ export class ExternalReference implements Comparable {
|
|
|
29
29
|
type: ExternalReferenceType
|
|
30
30
|
comment?: string
|
|
31
31
|
|
|
32
|
-
constructor (url:
|
|
32
|
+
constructor (url: ExternalReference['url'], type: ExternalReference['type'], op: OptionalProperties = {}) {
|
|
33
33
|
this.url = url
|
|
34
34
|
this.type = type
|
|
35
35
|
this.comment = op.comment
|
package/src/models/index.ts
CHANGED
package/src/models/license.ts
CHANGED
|
@@ -35,7 +35,7 @@ export class LicenseExpression {
|
|
|
35
35
|
/**
|
|
36
36
|
* @throws {RangeError} if {@see expression} is not eligible({@see LicenseExpression.isEligibleExpression})
|
|
37
37
|
*/
|
|
38
|
-
constructor (expression:
|
|
38
|
+
constructor (expression: LicenseExpression['expression']) {
|
|
39
39
|
this.expression = expression
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -68,7 +68,7 @@ export class NamedLicense {
|
|
|
68
68
|
text?: Attachment
|
|
69
69
|
url?: URL | string
|
|
70
70
|
|
|
71
|
-
constructor (name:
|
|
71
|
+
constructor (name: NamedLicense['name'], op: NamedLicenseOptionalProperties = {}) {
|
|
72
72
|
this.name = name
|
|
73
73
|
this.text = op.text
|
|
74
74
|
this.url = op.url
|
|
@@ -94,7 +94,7 @@ export class SpdxLicense {
|
|
|
94
94
|
/**
|
|
95
95
|
* @throws {RangeError} if {@see id} is not supported SPDX id({@see isSupportedSpdxId})
|
|
96
96
|
*/
|
|
97
|
-
constructor (id:
|
|
97
|
+
constructor (id: SpdxLicense['id'], op: SpdxLicenseOptionalProperties = {}) {
|
|
98
98
|
this.id = id
|
|
99
99
|
this.text = op.text
|
|
100
100
|
this.url = op.url
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
This file is part of CycloneDX JavaScript Library.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
|
|
16
|
+
SPDX-License-Identifier: Apache-2.0
|
|
17
|
+
Copyright (c) OWASP Foundation. All Rights Reserved.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { Comparable, SortableSet } from '../helpers/sortableSet'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @see {@link https://github.com/CycloneDX/cyclonedx-property-taxonomy property-taxonomy}
|
|
24
|
+
*/
|
|
25
|
+
export class Property implements Comparable {
|
|
26
|
+
name: string
|
|
27
|
+
value: string
|
|
28
|
+
|
|
29
|
+
constructor (name: Property['name'], value: Property['value']) {
|
|
30
|
+
this.name = name
|
|
31
|
+
this.value = value
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
compare (other: Property): number {
|
|
35
|
+
/* eslint-disable-next-line @typescript-eslint/strict-boolean-expressions -- run compares in weighted order */
|
|
36
|
+
return this.name.localeCompare(other.name) ||
|
|
37
|
+
this.value.localeCompare(other.value)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class PropertyRepository extends SortableSet<Property> {
|
|
42
|
+
}
|
package/src/models/swid.ts
CHANGED
|
@@ -45,7 +45,7 @@ export class SWID {
|
|
|
45
45
|
/**
|
|
46
46
|
* @throws {TypeError} if {@see op.tagVersion} is neither {@see NonNegativeInteger} nor {@see undefined}
|
|
47
47
|
*/
|
|
48
|
-
constructor (tagId:
|
|
48
|
+
constructor (tagId: SWID['tagId'], name: SWID['name'], op: OptionalProperties = {}) {
|
|
49
49
|
this.tagId = tagId
|
|
50
50
|
this.name = name
|
|
51
51
|
this.version = op.version
|
|
@@ -17,7 +17,7 @@ SPDX-License-Identifier: Apache-2.0
|
|
|
17
17
|
Copyright (c) OWASP Foundation. All Rights Reserved.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { Bom, BomRef } from '../models'
|
|
20
|
+
import { Component, Bom, BomRef } from '../models'
|
|
21
21
|
import { BomRefDiscriminator } from './bomRefDiscriminator'
|
|
22
22
|
import { NormalizerOptions, Serializer, SerializerOptions } from './types'
|
|
23
23
|
|
|
@@ -38,12 +38,19 @@ export abstract class BaseSerializer<NormalizedBom> implements Serializer {
|
|
|
38
38
|
|
|
39
39
|
#getAllBomRefs (bom: Bom): Iterable<BomRef> {
|
|
40
40
|
const bomRefs = new Set<BomRef>()
|
|
41
|
+
function iterComponents (cs: Iterable<Component>): void {
|
|
42
|
+
for (const { bomRef, components } of cs) {
|
|
43
|
+
bomRefs.add(bomRef)
|
|
44
|
+
iterComponents(components)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
if (bom.metadata.component !== undefined) {
|
|
42
49
|
bomRefs.add(bom.metadata.component.bomRef)
|
|
50
|
+
iterComponents(bom.metadata.component.components)
|
|
43
51
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
52
|
+
iterComponents(bom.components)
|
|
53
|
+
|
|
47
54
|
return bomRefs.values()
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -28,7 +28,7 @@ import { treeIterator } from '../../helpers/tree'
|
|
|
28
28
|
export class Factory {
|
|
29
29
|
readonly #spec: Spec
|
|
30
30
|
|
|
31
|
-
constructor (spec:
|
|
31
|
+
constructor (spec: Factory['spec']) {
|
|
32
32
|
this.#spec = spec
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -80,6 +80,10 @@ export class Factory {
|
|
|
80
80
|
return new AttachmentNormalizer(this)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
makeForProperty (): PropertyNormalizer {
|
|
84
|
+
return new PropertyNormalizer(this)
|
|
85
|
+
}
|
|
86
|
+
|
|
83
87
|
makeForDependencyGraph (): DependencyGraphNormalizer {
|
|
84
88
|
return new DependencyGraphNormalizer(this)
|
|
85
89
|
}
|
|
@@ -100,7 +104,7 @@ interface Normalizer {
|
|
|
100
104
|
abstract class Base implements Normalizer {
|
|
101
105
|
protected readonly _factory: Factory
|
|
102
106
|
|
|
103
|
-
constructor (factory:
|
|
107
|
+
constructor (factory: Base['factory']) {
|
|
104
108
|
this._factory = factory
|
|
105
109
|
}
|
|
106
110
|
|
|
@@ -199,7 +203,8 @@ export class HashNormalizer extends Base {
|
|
|
199
203
|
options.sortLists ?? false
|
|
200
204
|
? data.sorted()
|
|
201
205
|
: Array.from(data)
|
|
202
|
-
).map(
|
|
206
|
+
).map(
|
|
207
|
+
h => this.normalize(h, options)
|
|
203
208
|
).filter(isNotUndefined)
|
|
204
209
|
}
|
|
205
210
|
}
|
|
@@ -276,6 +281,9 @@ export class ComponentNormalizer extends Base {
|
|
|
276
281
|
externalReferences: data.externalReferences.size > 0
|
|
277
282
|
? this._factory.makeForExternalReference().normalizeRepository(data.externalReferences, options)
|
|
278
283
|
: undefined,
|
|
284
|
+
properties: spec.supportsProperties(data) && data.properties.size > 0
|
|
285
|
+
? this._factory.makeForProperty().normalizeRepository(data.properties, options)
|
|
286
|
+
: undefined,
|
|
279
287
|
components: data.components.size > 0
|
|
280
288
|
? this.normalizeRepository(data.components, options)
|
|
281
289
|
: undefined
|
|
@@ -288,7 +296,8 @@ export class ComponentNormalizer extends Base {
|
|
|
288
296
|
options.sortLists ?? false
|
|
289
297
|
? data.sorted()
|
|
290
298
|
: Array.from(data)
|
|
291
|
-
).map(
|
|
299
|
+
).map(
|
|
300
|
+
c => this.normalize(c, options)
|
|
292
301
|
).filter(isNotUndefined)
|
|
293
302
|
}
|
|
294
303
|
}
|
|
@@ -382,7 +391,8 @@ export class ExternalReferenceNormalizer extends Base {
|
|
|
382
391
|
options.sortLists ?? false
|
|
383
392
|
? data.sorted()
|
|
384
393
|
: Array.from(data)
|
|
385
|
-
).map(
|
|
394
|
+
).map(
|
|
395
|
+
r => this.normalize(r, options)
|
|
386
396
|
).filter(isNotUndefined)
|
|
387
397
|
}
|
|
388
398
|
}
|
|
@@ -397,6 +407,23 @@ export class AttachmentNormalizer extends Base {
|
|
|
397
407
|
}
|
|
398
408
|
}
|
|
399
409
|
|
|
410
|
+
export class PropertyNormalizer extends Base {
|
|
411
|
+
normalize (data: Models.Property, options: NormalizerOptions): Normalized.Property {
|
|
412
|
+
return {
|
|
413
|
+
name: data.name,
|
|
414
|
+
value: data.value
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
normalizeRepository (data: Models.PropertyRepository, options: NormalizerOptions): Normalized.Property[] {
|
|
419
|
+
return (
|
|
420
|
+
options.sortLists ?? false
|
|
421
|
+
? data.sorted()
|
|
422
|
+
: Array.from(data)
|
|
423
|
+
).map(p => this.normalize(p, options))
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
400
427
|
export class DependencyGraphNormalizer extends Base {
|
|
401
428
|
normalize (data: Models.Bom, options: NormalizerOptions): Normalized.Dependency[] | undefined {
|
|
402
429
|
const allRefs = new Map<Models.BomRef, Models.BomRefRepository>()
|
|
@@ -132,6 +132,7 @@ export namespace Normalized {
|
|
|
132
132
|
modified?: boolean
|
|
133
133
|
externalReferences?: ExternalReference[]
|
|
134
134
|
components?: Component[]
|
|
135
|
+
properties?: Property[]
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
export interface NamedLicense {
|
|
@@ -179,6 +180,11 @@ export namespace Normalized {
|
|
|
179
180
|
encoding?: Enums.AttachmentEncoding
|
|
180
181
|
}
|
|
181
182
|
|
|
183
|
+
export interface Property {
|
|
184
|
+
name?: string
|
|
185
|
+
value?: string
|
|
186
|
+
}
|
|
187
|
+
|
|
182
188
|
export interface Dependency {
|
|
183
189
|
ref: RefType
|
|
184
190
|
dependsOn?: RefType[]
|
|
@@ -33,7 +33,7 @@ export class JsonSerializer extends BaseSerializer<Normalized.Bom> {
|
|
|
33
33
|
/**
|
|
34
34
|
* @throws {UnsupportedFormatError} if {@see normalizerFactory.spec} does not support {@see Format.JSON}.
|
|
35
35
|
*/
|
|
36
|
-
constructor (normalizerFactory:
|
|
36
|
+
constructor (normalizerFactory: JsonSerializer['normalizerFactory']) {
|
|
37
37
|
if (!normalizerFactory.spec.supportsFormat(Format.JSON)) {
|
|
38
38
|
throw new UnsupportedFormatError('Spec does not support JSON format.')
|
|
39
39
|
}
|
|
@@ -28,7 +28,7 @@ import { treeIterator } from '../../helpers/tree'
|
|
|
28
28
|
export class Factory {
|
|
29
29
|
readonly #spec: Spec
|
|
30
30
|
|
|
31
|
-
constructor (spec:
|
|
31
|
+
constructor (spec: Factory['spec']) {
|
|
32
32
|
this.#spec = spec
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -80,6 +80,10 @@ export class Factory {
|
|
|
80
80
|
return new AttachmentNormalizer(this)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
makeForProperty (): PropertyNormalizer {
|
|
84
|
+
return new PropertyNormalizer(this)
|
|
85
|
+
}
|
|
86
|
+
|
|
83
87
|
makeForDependencyGraph (): DependencyGraphNormalizer {
|
|
84
88
|
return new DependencyGraphNormalizer(this)
|
|
85
89
|
}
|
|
@@ -100,7 +104,7 @@ interface Normalizer {
|
|
|
100
104
|
abstract class Base implements Normalizer {
|
|
101
105
|
protected readonly _factory: Factory
|
|
102
106
|
|
|
103
|
-
constructor (factory:
|
|
107
|
+
constructor (factory: Base['factory']) {
|
|
104
108
|
this._factory = factory
|
|
105
109
|
}
|
|
106
110
|
|
|
@@ -256,7 +260,8 @@ export class HashNormalizer extends Base {
|
|
|
256
260
|
options.sortLists ?? false
|
|
257
261
|
? data.sorted()
|
|
258
262
|
: Array.from(data)
|
|
259
|
-
).map(
|
|
263
|
+
).map(
|
|
264
|
+
h => this.normalize(h, options, elementName)
|
|
260
265
|
).filter(isNotUndefined)
|
|
261
266
|
}
|
|
262
267
|
}
|
|
@@ -340,6 +345,13 @@ export class ComponentNormalizer extends Base {
|
|
|
340
345
|
.normalizeRepository(data.externalReferences, options, 'reference')
|
|
341
346
|
}
|
|
342
347
|
: undefined
|
|
348
|
+
const properties: SimpleXml.Element | undefined = spec.supportsProperties(data) && data.properties.size > 0
|
|
349
|
+
? {
|
|
350
|
+
type: 'element',
|
|
351
|
+
name: 'properties',
|
|
352
|
+
children: this._factory.makeForProperty().normalizeRepository(data.properties, options, 'property')
|
|
353
|
+
}
|
|
354
|
+
: undefined
|
|
343
355
|
const components: SimpleXml.Element | undefined = data.components.size > 0
|
|
344
356
|
? {
|
|
345
357
|
type: 'element',
|
|
@@ -370,6 +382,7 @@ export class ComponentNormalizer extends Base {
|
|
|
370
382
|
makeOptionalTextElement(data.purl, 'purl'),
|
|
371
383
|
swid,
|
|
372
384
|
extRefs,
|
|
385
|
+
properties,
|
|
373
386
|
components
|
|
374
387
|
].filter(isNotUndefined)
|
|
375
388
|
}
|
|
@@ -380,7 +393,8 @@ export class ComponentNormalizer extends Base {
|
|
|
380
393
|
options.sortLists ?? false
|
|
381
394
|
? data.sorted()
|
|
382
395
|
: Array.from(data)
|
|
383
|
-
).map(
|
|
396
|
+
).map(
|
|
397
|
+
c => this.normalize(c, options, elementName)
|
|
384
398
|
).filter(isNotUndefined)
|
|
385
399
|
}
|
|
386
400
|
}
|
|
@@ -498,7 +512,8 @@ export class ExternalReferenceNormalizer extends Base {
|
|
|
498
512
|
options.sortLists ?? false
|
|
499
513
|
? data.sorted()
|
|
500
514
|
: Array.from(data)
|
|
501
|
-
).map(
|
|
515
|
+
).map(
|
|
516
|
+
r => this.normalize(r, options, elementName)
|
|
502
517
|
).filter(isNotUndefined)
|
|
503
518
|
}
|
|
504
519
|
}
|
|
@@ -517,6 +532,27 @@ export class AttachmentNormalizer extends Base {
|
|
|
517
532
|
}
|
|
518
533
|
}
|
|
519
534
|
|
|
535
|
+
export class PropertyNormalizer extends Base {
|
|
536
|
+
normalize (data: Models.Property, options: NormalizerOptions, elementName: string): SimpleXml.Element {
|
|
537
|
+
return {
|
|
538
|
+
type: 'element',
|
|
539
|
+
name: elementName,
|
|
540
|
+
attributes: {
|
|
541
|
+
name: data.name
|
|
542
|
+
},
|
|
543
|
+
children: data.value
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
normalizeRepository (data: Models.PropertyRepository, options: NormalizerOptions, elementName: string): SimpleXml.Element[] {
|
|
548
|
+
return (
|
|
549
|
+
options.sortLists ?? false
|
|
550
|
+
? data.sorted()
|
|
551
|
+
: Array.from(data)
|
|
552
|
+
).map(p => this.normalize(p, options, elementName))
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
520
556
|
export class DependencyGraphNormalizer extends Base {
|
|
521
557
|
normalize (data: Models.Bom, options: NormalizerOptions, elementName: string): SimpleXml.Element | undefined {
|
|
522
558
|
const allRefs = new Map<Models.BomRef, Models.BomRefRepository>()
|
|
@@ -33,7 +33,7 @@ export abstract class XmlBaseSerializer extends BaseSerializer<SimpleXml.Element
|
|
|
33
33
|
/**
|
|
34
34
|
* @throws {UnsupportedFormatError} if {@see normalizerFactory.spec} does not support {@see Format.XML}.
|
|
35
35
|
*/
|
|
36
|
-
constructor (normalizerFactory:
|
|
36
|
+
constructor (normalizerFactory: XmlBaseSerializer['normalizerFactory']) {
|
|
37
37
|
if (!normalizerFactory.spec.supportsFormat(Format.JSON)) {
|
|
38
38
|
throw new UnsupportedFormatError('Spec does not support JSON format.')
|
|
39
39
|
}
|
package/src/spec.ts
CHANGED
|
@@ -37,28 +37,21 @@ export class UnsupportedFormatError extends Error {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export interface Protocol {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
version: Version
|
|
42
41
|
supportsFormat: (f: Format | any) => boolean
|
|
43
|
-
|
|
44
42
|
supportsComponentType: (ct: ComponentType | any) => boolean
|
|
45
|
-
|
|
46
43
|
supportsHashAlgorithm: (ha: HashAlgorithm | any) => boolean
|
|
47
|
-
|
|
48
44
|
supportsHashValue: (hv: HashContent | any) => boolean
|
|
49
|
-
|
|
50
45
|
supportsExternalReferenceType: (ert: ExternalReferenceType | any) => boolean
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
readonly requiresComponentVersion: boolean
|
|
46
|
+
supportsDependencyGraph: boolean
|
|
47
|
+
supportsToolReferences: boolean
|
|
48
|
+
requiresComponentVersion: boolean
|
|
49
|
+
supportsProperties: (model: any) => boolean
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
/**
|
|
60
|
-
* @internal This class was never intended to be public,
|
|
61
|
-
*
|
|
53
|
+
* @internal This class was never intended to be public, but
|
|
54
|
+
* it is a helper to get the exact spec-versions implemented according to {@see Protocol}.
|
|
62
55
|
*/
|
|
63
56
|
class Spec implements Protocol {
|
|
64
57
|
readonly #version: Version
|
|
@@ -70,6 +63,7 @@ class Spec implements Protocol {
|
|
|
70
63
|
readonly #supportsDependencyGraph: boolean
|
|
71
64
|
readonly #supportsToolReferences: boolean
|
|
72
65
|
readonly #requiresComponentVersion: boolean
|
|
66
|
+
readonly #supportsProperties: boolean
|
|
73
67
|
|
|
74
68
|
constructor (
|
|
75
69
|
version: Version,
|
|
@@ -80,7 +74,8 @@ class Spec implements Protocol {
|
|
|
80
74
|
externalReferenceTypes: Iterable<ExternalReferenceType>,
|
|
81
75
|
supportsDependencyGraph: boolean,
|
|
82
76
|
supportsToolReferences: boolean,
|
|
83
|
-
requiresComponentVersion: boolean
|
|
77
|
+
requiresComponentVersion: boolean,
|
|
78
|
+
supportsProperties: boolean
|
|
84
79
|
) {
|
|
85
80
|
this.#version = version
|
|
86
81
|
this.#formats = new Set(formats)
|
|
@@ -91,6 +86,7 @@ class Spec implements Protocol {
|
|
|
91
86
|
this.#supportsDependencyGraph = supportsDependencyGraph
|
|
92
87
|
this.#supportsToolReferences = supportsToolReferences
|
|
93
88
|
this.#requiresComponentVersion = requiresComponentVersion
|
|
89
|
+
this.#supportsProperties = supportsProperties
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
get version (): Version {
|
|
@@ -129,6 +125,11 @@ class Spec implements Protocol {
|
|
|
129
125
|
get requiresComponentVersion (): boolean {
|
|
130
126
|
return this.#requiresComponentVersion
|
|
131
127
|
}
|
|
128
|
+
|
|
129
|
+
supportsProperties (): boolean {
|
|
130
|
+
// currently a global allow/deny -- might work based on input, in the future
|
|
131
|
+
return this.#supportsProperties
|
|
132
|
+
}
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
/** Specification v1.2 */
|
|
@@ -182,7 +183,8 @@ export const Spec1dot2: Readonly<Protocol> = Object.freeze(new Spec(
|
|
|
182
183
|
],
|
|
183
184
|
true,
|
|
184
185
|
false,
|
|
185
|
-
true
|
|
186
|
+
true,
|
|
187
|
+
false
|
|
186
188
|
))
|
|
187
189
|
|
|
188
190
|
/** Specification v1.3 */
|
|
@@ -236,6 +238,7 @@ export const Spec1dot3: Readonly<Protocol> = Object.freeze(new Spec(
|
|
|
236
238
|
],
|
|
237
239
|
true,
|
|
238
240
|
false,
|
|
241
|
+
true,
|
|
239
242
|
true
|
|
240
243
|
))
|
|
241
244
|
|
|
@@ -291,11 +294,14 @@ export const Spec1dot4: Readonly<Protocol> = Object.freeze(new Spec(
|
|
|
291
294
|
],
|
|
292
295
|
true,
|
|
293
296
|
true,
|
|
294
|
-
false
|
|
297
|
+
false,
|
|
298
|
+
true
|
|
295
299
|
))
|
|
296
300
|
|
|
297
|
-
export const SpecVersionDict = Object.freeze(
|
|
298
|
-
[
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
export const SpecVersionDict: { readonly [key in Version]?: Readonly<Protocol> } = Object.freeze(
|
|
302
|
+
Object.fromEntries([
|
|
303
|
+
[Version.v1dot2, Spec1dot2],
|
|
304
|
+
[Version.v1dot3, Spec1dot3],
|
|
305
|
+
[Version.v1dot4, Spec1dot4]
|
|
306
|
+
])
|
|
307
|
+
)
|