Skip to content

Commit e3cdbce

Browse files
authored
Models.Properties & Models.Component.properties (#151)
models for Properties & component.properties * Models for `Property`, `PropertyRepository`. * JSON- and XML-Normalizers for `Models.Property`, `Models.PropertyRepository`. * New property `Models.Component.properties`. Signed-off-by: Jan Kowalleck <[email protected]>
1 parent 39a8080 commit e3cdbce

20 files changed

+463
-2
lines changed

HISTORY.md

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
44

55
## unreleased
66

7+
* Added
8+
* Models for `Property` and `PropertyRepository`. (via [#151])
9+
* JSON- and XML-Normalizer for `Models.Property`, `Models.PropertyRepository`. (via [#151])
10+
* New property `Models.Component.properties`. (via [#151])
11+
12+
[#151]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/151
13+
714
## 1.2.0 - 2022-08-01
815

916
* Added

src/models/component.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { OrganizationalEntity } from './organizationalEntity'
2727
import { ExternalReferenceRepository } from './externalReference'
2828
import { LicenseRepository } from './license'
2929
import { SWID } from './swid'
30+
import { PropertyRepository } from './property'
3031
import { Comparable, SortableSet } from '../helpers/sortableSet'
3132
import { treeIterator } from '../helpers/tree'
3233

@@ -48,6 +49,7 @@ interface OptionalProperties {
4849
dependencies?: Component['dependencies']
4950
components?: Component['components']
5051
cpe?: Component['cpe']
52+
properties?: Component['properties']
5153
}
5254

5355
export class Component implements Comparable {
@@ -68,6 +70,7 @@ export class Component implements Comparable {
6870
version?: string
6971
dependencies: BomRefRepository
7072
components: ComponentRepository
73+
properties: PropertyRepository
7174

7275
/** @see bomRef */
7376
readonly #bomRef: BomRef
@@ -78,7 +81,7 @@ export class Component implements Comparable {
7881
/**
7982
* @throws {TypeError} if {@see op.cpe} is neither {@see CPE} nor {@see undefined}
8083
*/
81-
constructor (type: ComponentType, name: string, op: OptionalProperties = {}) {
84+
constructor (type: Component['type'], name: Component['name'], op: OptionalProperties = {}) {
8285
this.#bomRef = new BomRef(op.bomRef)
8386
this.type = type
8487
this.name = name
@@ -98,6 +101,7 @@ export class Component implements Comparable {
98101
this.dependencies = op.dependencies ?? new BomRefRepository()
99102
this.components = op.components ?? new ComponentRepository()
100103
this.cpe = op.cpe
104+
this.properties = op.properties ?? new PropertyRepository()
101105
}
102106

103107
get bomRef (): BomRef {

src/models/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ export * from './license'
2727
export * from './metadata'
2828
export * from './organizationalContact'
2929
export * from './organizationalEntity'
30+
export * from './property'
3031
export * from './swid'
3132
export * from './tool'

src/models/property.ts

+42
Original file line numberDiff line numberDiff line change
@@ -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+
}

src/serialize/json/normalize.ts

+24
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ export class Factory {
8080
return new AttachmentNormalizer(this)
8181
}
8282

83+
makeForProperty (): PropertyNormalizer {
84+
return new PropertyNormalizer(this)
85+
}
86+
8387
makeForDependencyGraph (): DependencyGraphNormalizer {
8488
return new DependencyGraphNormalizer(this)
8589
}
@@ -278,6 +282,9 @@ export class ComponentNormalizer extends Base {
278282
: undefined,
279283
components: data.components.size > 0
280284
? this.normalizeRepository(data.components, options)
285+
: undefined,
286+
properties: data.properties.size > 0
287+
? this._factory.makeForProperty().normalizeRepository(data.properties, options)
281288
: undefined
282289
}
283290
: undefined
@@ -397,6 +404,23 @@ export class AttachmentNormalizer extends Base {
397404
}
398405
}
399406

407+
export class PropertyNormalizer extends Base {
408+
normalize (data: Models.Property, options: NormalizerOptions): Normalized.Property {
409+
return {
410+
name: data.name,
411+
value: data.value
412+
}
413+
}
414+
415+
normalizeRepository (data: Models.PropertyRepository, options: NormalizerOptions): Normalized.Property[] {
416+
return (
417+
options.sortLists ?? false
418+
? data.sorted()
419+
: Array.from(data)
420+
).map(p => this.normalize(p, options))
421+
}
422+
}
423+
400424
export class DependencyGraphNormalizer extends Base {
401425
normalize (data: Models.Bom, options: NormalizerOptions): Normalized.Dependency[] | undefined {
402426
const allRefs = new Map<Models.BomRef, Models.BomRefRepository>()

src/serialize/json/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export namespace Normalized {
132132
modified?: boolean
133133
externalReferences?: ExternalReference[]
134134
components?: Component[]
135+
properties?: Property[]
135136
}
136137

137138
export interface NamedLicense {
@@ -179,6 +180,11 @@ export namespace Normalized {
179180
encoding?: Enums.AttachmentEncoding
180181
}
181182

183+
export interface Property {
184+
name?: string
185+
value?: string
186+
}
187+
182188
export interface Dependency {
183189
ref: RefType
184190
dependsOn?: RefType[]

src/serialize/xml/normalize.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ export class Factory {
8080
return new AttachmentNormalizer(this)
8181
}
8282

83+
makeForProperty (): PropertyNormalizer {
84+
return new PropertyNormalizer(this)
85+
}
86+
8387
makeForDependencyGraph (): DependencyGraphNormalizer {
8488
return new DependencyGraphNormalizer(this)
8589
}
@@ -347,6 +351,13 @@ export class ComponentNormalizer extends Base {
347351
children: this.normalizeRepository(data.components, options, 'component')
348352
}
349353
: undefined
354+
const properties: SimpleXml.Element | undefined = data.properties.size > 0
355+
? {
356+
type: 'element',
357+
name: 'properties',
358+
children: this._factory.makeForProperty().normalizeRepository(data.properties, options, 'property')
359+
}
360+
: undefined
350361
return {
351362
type: 'element',
352363
name: elementName,
@@ -370,7 +381,8 @@ export class ComponentNormalizer extends Base {
370381
makeOptionalTextElement(data.purl, 'purl'),
371382
swid,
372383
extRefs,
373-
components
384+
components,
385+
properties
374386
].filter(isNotUndefined)
375387
}
376388
}
@@ -517,6 +529,27 @@ export class AttachmentNormalizer extends Base {
517529
}
518530
}
519531

532+
export class PropertyNormalizer extends Base {
533+
normalize (data: Models.Property, options: NormalizerOptions, elementName: string): SimpleXml.Element {
534+
return {
535+
type: 'element',
536+
name: elementName,
537+
attributes: {
538+
name: data.name
539+
},
540+
children: data.value
541+
}
542+
}
543+
544+
normalizeRepository (data: Models.PropertyRepository, options: NormalizerOptions, elementName: string): SimpleXml.Element[] {
545+
return (
546+
options.sortLists ?? false
547+
? data.sorted()
548+
: Array.from(data)
549+
).map(p => this.normalize(p, options, elementName))
550+
}
551+
}
552+
520553
export class DependencyGraphNormalizer extends Base {
521554
normalize (data: Models.Bom, options: NormalizerOptions, elementName: string): SimpleXml.Element | undefined {
522555
const allRefs = new Map<Models.BomRef, Models.BomRefRepository>()

tests/_data/models.js

+10
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,15 @@ module.exports.createComplexStructure = function () {
186186
bomRef: 'SomeFrameworkBundle'
187187
})))
188188

189+
bom.components.add(new Models.Component(
190+
Enums.ComponentType.Library, 'component-with-properties', {
191+
bomRef: 'ComponentWithProperties',
192+
properties: new Models.PropertyRepository([
193+
new Models.Property('internal:testing:prop-Z', 'value Z'),
194+
new Models.Property('internal:testing:prop-Z', 'value B'),
195+
new Models.Property('internal:testing:prop-A', 'value A')
196+
])
197+
}))
198+
189199
return bom
190200
}

tests/_data/normalizeResults/json_sortedLists_spec1.2.json

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/_data/normalizeResults/json_sortedLists_spec1.3.json

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/_data/normalizeResults/json_sortedLists_spec1.4.json

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)