Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ written in _TypeScript_ and compiled for the target.

## Capabilities

* Enums for the following use cases
* Enums for the following use cases:
* `AttachmentEncoding`
* `ComponentScope`
* `ComponentType`
* `ExternalReferenceType`
* `HashAlgorithm`
* Data models for the following use cases
* Data models for the following use cases:
* `Attachment`
* `Bom`
* `BomRef`, `BomRefRepository`
Expand All @@ -51,7 +51,11 @@ written in _TypeScript_ and compiled for the target.
* `OrganizationalEntity`
* `SWID`
* `Tool`, `ToolRepository`
* Factory, that can create data models from any license descriptor string
* Factories for the following use cases:
* Create data models from any license descriptor string
* Specific to _Node.js_: create data models from PackageJson-like data structures
* Builders for the following use cases:
* Specific to _Node.js_: create deep data models from PackageJson-like data structures
* Implementation of the [_CycloneDX_ Specification][CycloneDX-spec] for the following versions:
* `1.4`
* `1.3`
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@
"xmlbuilder2": "^3.0.2"
},
"browser": "./dist.web/lib.js",
"types": "./src/_index.node.ts",
"main": "./dist.node/_index.node.js",
"exports": "./dist.node/_index.node.js",
"types": "./src/index.node.ts",
"main": "./dist.node/index.node.js",
"exports": "./dist.node/index.node.js",
"directories": {
"doc": "./docs",
"src": "./src",
Expand Down
128 changes: 128 additions & 0 deletions src/builders/fromPackageJson.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

import { PackageURL } from 'packageurl-js'

import * as Enums from '../enums'
import { ExternalReferenceType } from '../enums'
import * as Models from '../models'
import * as Factories from '../factories/index.node'
import { PackageJson, splitNameGroup } from '../helpers/packageJson'

/**
* @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json PackageJson spec}
*/

export class ToolBuilder {
readonly #extRefFactory: Factories.FromPackageJson.ExternalReferenceFactory

constructor (extRefFactory: Factories.FromPackageJson.ExternalReferenceFactory) {
this.#extRefFactory = extRefFactory
}

makeTool (data: PackageJson): Models.Tool | undefined {
const [name, vendor] = typeof data.name === 'string'
? splitNameGroup(data.name)
: []

return new Models.Tool({
vendor,
name,
version: (typeof data.version === 'string')
? data.version
: undefined,
externalReferences: new Models.ExternalReferenceRepository(this.#extRefFactory.makeExternalReferences(data))
})
}
}

export class ComponentBuilder {
readonly #extRefFactory: Factories.FromPackageJson.ExternalReferenceFactory
readonly #licenseFactory: Factories.LicenseFactory

constructor (extRefFactory: Factories.FromPackageJson.ExternalReferenceFactory, licenseFactory: Factories.LicenseFactory) {
this.#extRefFactory = extRefFactory
this.#licenseFactory = licenseFactory
}

makeComponent (data: PackageJson, type: Enums.ComponentType = Enums.ComponentType.Library): Models.Component | undefined {
if (typeof data.name !== 'string') {
return undefined
}

const [name, group] = splitNameGroup(data.name)
if (name.length === 0) {
return undefined
}

/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#author} */
const author = typeof data.author === 'string'
? data.author
: (typeof data.author?.name === 'string'
? data.author.name
: undefined)
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#description-1} */
const description = typeof data.description === 'string'
? data.description
: undefined
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#version} */
const version = typeof data.version === 'string'
? data.version
: undefined
const externalReferences = this.#extRefFactory.makeExternalReferences(data)
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#license} */
const license = typeof data.license === 'string'
? this.#licenseFactory.makeFromString(data.license)
: undefined

return new Models.Component(type, name, {
author,
description,
externalReferences: new Models.ExternalReferenceRepository(externalReferences),
group,
licenses: new Models.LicenseRepository(
license === undefined
? []
: [license]
),
version,
purl: this.#makePurl(name, group, version, externalReferences)
})
}

#makePurl (
name: string,
group: string | undefined,
version: string | undefined,
externalReferences: Models.ExternalReference[]
): PackageURL {
const qualifiers: { [key: string]: string } = {}
const subpath = undefined

const vcsUrl = externalReferences.filter(
({ type }) => type === ExternalReferenceType.VCS
)[0]?.url.toString()
if (vcsUrl !== undefined) {
qualifiers.vcs_url = vcsUrl
}

return new PackageURL(
'npm', group, name, version, qualifiers, subpath)
}
}
20 changes: 20 additions & 0 deletions src/builders/index.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

export * as FromPackageJson from './fromPackageJson.node'
88 changes: 88 additions & 0 deletions src/factories/fromPackageJson.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

import * as Models from '../models'
import * as Enums from '../enums'
import { isNotUndefined } from '../helpers/notUndefined'
import { PackageJson } from '../helpers/packageJson'

/**
* @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json PackageJson spec}
*/

export class ExternalReferenceFactory {
makeExternalReferences (data: PackageJson): Models.ExternalReference[] {
const refs: Array<Models.ExternalReference | undefined> = []

try { refs.push(this.makeVcs(data)) } catch { /* pass */ }
try { refs.push(this.makeHomepage(data)) } catch { /* pass */ }
try { refs.push(this.makeIssueTracker(data)) } catch { /* pass */ }

return refs.filter(isNotUndefined)
}

makeVcs (data: PackageJson): Models.ExternalReference | undefined {
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#repository the spec} */
const repository = data.repository
let url
let comment: string | undefined
if (typeof repository === 'object') {
url = repository.url
comment = 'as detected from PackageJson property "repository.url"'
if (typeof repository.directory === 'string' && typeof url === 'string' && url.length > 0) {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
url += '#' + repository.directory
comment += ' and "repository.directory"'
}
} else {
url = repository
comment = 'as detected from PackageJson property "repository"'
}
return typeof url === 'string' && url.length > 0
? new Models.ExternalReference(url, Enums.ExternalReferenceType.VCS, { comment })
: undefined
}

makeHomepage (data: PackageJson): Models.ExternalReference | undefined {
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#homepage the spec} */
const url = data.homepage
return typeof url === 'string' && url.length > 0
? new Models.ExternalReference(
url, Enums.ExternalReferenceType.Website,
{ comment: 'as detected from PackageJson property "homepage"' })
: undefined
}

makeIssueTracker (data: PackageJson): Models.ExternalReference | undefined {
/** @see {@link https://docs.npmjs.com/cli/v8/configuring-npm/package-json#bugs the spec} */
const bugs = data.bugs
let url
let comment: string | undefined
if (typeof bugs === 'object') {
url = bugs.url
comment = 'as detected from PackageJson property "bugs.url"'
} else {
url = bugs
comment = 'as detected from PackageJson property "bugs"'
}
return typeof url === 'string' && url.length > 0
? new Models.ExternalReference(url, Enums.ExternalReferenceType.IssueTracker, { comment })
: undefined
}
}
22 changes: 22 additions & 0 deletions src/factories/index.common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

// not everything is public, yet

export * from './license'
22 changes: 22 additions & 0 deletions src/factories/index.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

export * from './index.common'

export * as FromPackageJson from './fromPackageJson.node'
2 changes: 1 addition & 1 deletion src/factories/index.ts → src/factories/index.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

export * from './licenseFactory'
export * from './index.common'
File renamed without changes.
48 changes: 48 additions & 0 deletions src/helpers/packageJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

/**
* Split name and group from a package's name.
* Returns a tuple: [name, ?group]
*/
export function splitNameGroup (data: string): [string, string?] {
return data[0] === '@'
? data.split('/', 2).reverse() as [string, string?]
: [data]
}

export interface PackageJson {
name?: string
version?: string
description?: string
license?: string
author?: string | {
name?: string
email?: string
}
bugs?: string | {
url?: string
}
homepage?: string
repository?: string | {
url?: string
directory?: string
}
// .. to be continued
}
Loading