diff --git a/README.md b/README.md index eba49cf9d..18ae56beb 100644 --- a/README.md +++ b/README.md @@ -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` @@ -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` diff --git a/package.json b/package.json index 5e4fd1431..ba1a9283d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/builders/fromPackageJson.node.ts b/src/builders/fromPackageJson.node.ts new file mode 100644 index 000000000..5dfe1d779 --- /dev/null +++ b/src/builders/fromPackageJson.node.ts @@ -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) + } +} diff --git a/src/builders/index.node.ts b/src/builders/index.node.ts new file mode 100644 index 000000000..99fb91211 --- /dev/null +++ b/src/builders/index.node.ts @@ -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' diff --git a/src/factories/fromPackageJson.node.ts b/src/factories/fromPackageJson.node.ts new file mode 100644 index 000000000..96e050d78 --- /dev/null +++ b/src/factories/fromPackageJson.node.ts @@ -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 = [] + + 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 + } +} diff --git a/src/factories/index.common.ts b/src/factories/index.common.ts new file mode 100644 index 000000000..f42c47230 --- /dev/null +++ b/src/factories/index.common.ts @@ -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' diff --git a/src/factories/index.node.ts b/src/factories/index.node.ts new file mode 100644 index 000000000..e52491ba0 --- /dev/null +++ b/src/factories/index.node.ts @@ -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' diff --git a/src/factories/index.ts b/src/factories/index.web.ts similarity index 95% rename from src/factories/index.ts rename to src/factories/index.web.ts index f1a3707f5..392192afa 100644 --- a/src/factories/index.ts +++ b/src/factories/index.web.ts @@ -17,4 +17,4 @@ SPDX-License-Identifier: Apache-2.0 Copyright (c) OWASP Foundation. All Rights Reserved. */ -export * from './licenseFactory' +export * from './index.common' diff --git a/src/factories/licenseFactory.ts b/src/factories/license.ts similarity index 100% rename from src/factories/licenseFactory.ts rename to src/factories/license.ts diff --git a/src/helpers/packageJson.ts b/src/helpers/packageJson.ts new file mode 100644 index 000000000..b98f2fba2 --- /dev/null +++ b/src/helpers/packageJson.ts @@ -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 +} diff --git a/src/_index.node.ts b/src/index.node.ts similarity index 82% rename from src/_index.node.ts rename to src/index.node.ts index 6ba6b9389..6f937714d 100644 --- a/src/_index.node.ts +++ b/src/index.node.ts @@ -17,15 +17,16 @@ SPDX-License-Identifier: Apache-2.0 Copyright (c) OWASP Foundation. All Rights Reserved. */ +export * as Builders from './builders/index.node' export * as Enums from './enums' -export * as Factories from './factories' +export * as Factories from './factories/index.node' export * as Models from './models' -export * as Serialize from './serialize/_index.node' +export * as Serialize from './serialize/index.node' export * as SPDX from './spdx' export * as Spec from './spec' export * as Types from './types' /** @internal until the resources-module was finalized and showed value */ -export * as Resources from './resources.node' +export * as _Resources from './resources.node' // do not export the helpers, they are for internal use only diff --git a/src/_index.web.ts b/src/index.web.ts similarity index 89% rename from src/_index.web.ts rename to src/index.web.ts index 59f3d8734..d1cc904f7 100644 --- a/src/_index.web.ts +++ b/src/index.web.ts @@ -21,7 +21,7 @@ export * as Types from './types' export * as Enums from './enums' export * as SPDX from './spdx' export * as Models from './models' -export * as Factories from './factories' +export * as Factories from './factories/index.web' export * as Spec from './spec' -export * as Serialize from './serialize/_index.web' +export * as Serialize from './serialize/index.web' // do not export the helpers, they are for internal use only diff --git a/src/serialize/index.ts b/src/serialize/index.common.ts similarity index 100% rename from src/serialize/index.ts rename to src/serialize/index.common.ts diff --git a/src/serialize/_index.node.ts b/src/serialize/index.node.ts similarity index 96% rename from src/serialize/_index.node.ts rename to src/serialize/index.node.ts index 5a6bdde8e..9f1250a4e 100644 --- a/src/serialize/_index.node.ts +++ b/src/serialize/index.node.ts @@ -17,7 +17,7 @@ SPDX-License-Identifier: Apache-2.0 Copyright (c) OWASP Foundation. All Rights Reserved. */ -export * from './index' +export * from './index.common' export * from './xmlSerializer.node' // export * from './xmlDeserializer.node' // TODO diff --git a/src/serialize/_index.web.ts b/src/serialize/index.web.ts similarity index 96% rename from src/serialize/_index.web.ts rename to src/serialize/index.web.ts index 9a16739f7..1902b12af 100644 --- a/src/serialize/_index.web.ts +++ b/src/serialize/index.web.ts @@ -17,7 +17,7 @@ SPDX-License-Identifier: Apache-2.0 Copyright (c) OWASP Foundation. All Rights Reserved. */ -export * from './index' +export * from './index.common' export * from './xmlSerializer.web' // export * from './xmlDeserializer.web' // TODO diff --git a/tests/_data/spdx.js b/tests/_data/spdx.js index 477705168..fd7ce610d 100644 --- a/tests/_data/spdx.js +++ b/tests/_data/spdx.js @@ -21,7 +21,7 @@ Copyright (c) OWASP Foundation. All Rights Reserved. const fs = require('fs') const assert = require('assert') -const { Resources: { FILES: { SPDX: { JSON_SCHEMA: SPDX_JSON_SCHEMA } } } } = require('../../') +const { _Resources: { FILES: { SPDX: { JSON_SCHEMA: SPDX_JSON_SCHEMA } } } } = require('../../') const spdxSpecEnum = JSON.parse(fs.readFileSync( SPDX_JSON_SCHEMA diff --git a/tests/functional/Enums.ComponentScope.spec.js b/tests/functional/Enums.ComponentScope.spec.js index e573aedc7..10bba6aaf 100644 --- a/tests/functional/Enums.ComponentScope.spec.js +++ b/tests/functional/Enums.ComponentScope.spec.js @@ -27,7 +27,7 @@ const { upperCamelCase } = require('../_helpers/stringFunctions') const { Enums: { ComponentScope }, Spec: { Version }, - Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } + _Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } } = require('../../') suite('ComponentScope enum', () => { diff --git a/tests/functional/Enums.ComponentType.spec.js b/tests/functional/Enums.ComponentType.spec.js index 445516032..e121744dc 100644 --- a/tests/functional/Enums.ComponentType.spec.js +++ b/tests/functional/Enums.ComponentType.spec.js @@ -27,7 +27,7 @@ const { upperCamelCase } = require('../_helpers/stringFunctions') const { Enums: { ComponentType }, Spec: { Version, SpecVersionDict }, - Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } + _Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } } = require('../../') suite('ComponentType enum', () => { diff --git a/tests/functional/Enums.ExternalReferenceType.spec.js b/tests/functional/Enums.ExternalReferenceType.spec.js index 8e454c9f3..4d4d29084 100644 --- a/tests/functional/Enums.ExternalReferenceType.spec.js +++ b/tests/functional/Enums.ExternalReferenceType.spec.js @@ -27,7 +27,7 @@ const { upperCamelCase } = require('../_helpers/stringFunctions') const { Enums: { ExternalReferenceType }, Spec: { Version, SpecVersionDict }, - Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } + _Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } } = require('../../') suite('ExternalReferenceType enum', () => { diff --git a/tests/functional/Enums.HashAlogorithms.spec.js b/tests/functional/Enums.HashAlogorithms.spec.js index b71ef55fc..ed1570eef 100644 --- a/tests/functional/Enums.HashAlogorithms.spec.js +++ b/tests/functional/Enums.HashAlogorithms.spec.js @@ -27,7 +27,7 @@ const { capitaliseFirstLetter } = require('../_helpers/stringFunctions') const { Enums: { HashAlgorithm }, Spec: { Version, SpecVersionDict }, - Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } + _Resources: { FILES: { CDX: { JSON_SCHEMA: CDX_JSON_SCHEMA } } } } = require('../../') suite('HashAlgorithm enum', () => { diff --git a/tests/functional/Resources.node.spec.js b/tests/functional/Resources.node.spec.js index 4d30fed0f..7b2cae5e9 100644 --- a/tests/functional/Resources.node.spec.js +++ b/tests/functional/Resources.node.spec.js @@ -23,7 +23,7 @@ const assert = require('assert') const { suite, test } = require('mocha') const { - Resources, + _Resources: Resources, Spec: { Version } } = require('../../') diff --git a/tests/integration/Builders.FromPackageJson.ComponentBuilder.test.js b/tests/integration/Builders.FromPackageJson.ComponentBuilder.test.js new file mode 100644 index 000000000..785baea23 --- /dev/null +++ b/tests/integration/Builders.FromPackageJson.ComponentBuilder.test.js @@ -0,0 +1,72 @@ +'use strict' +/*! +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. +*/ + +const assert = require('assert') +const { suite, test } = require('mocha') + +const { PackageURL } = require('packageurl-js') + +const { + Enums, + Models, + Factories, + Builders: { FromPackageJson: { ComponentBuilder } } +} = require('../../') + +suite('Builders.FromPackageJson.ComponentBuilder', () => { + const salt = Math.random() + + const extRefFactory = new Factories.FromPackageJson.ExternalReferenceFactory() + extRefFactory.makeExternalReferences = () => [`FAKE REFERENCES ${salt}`] + const licenseFactory = new Factories.LicenseFactory() + licenseFactory.makeFromString = () => `FAKE LICENSE ${salt}` + + const sut = new ComponentBuilder(extRefFactory, licenseFactory) + + const data = { + name: '@foo/bar', + version: `1.33.7-alpha.23.${salt}`, + description: `dummy lib ${salt}`, + author: { + name: 'Jane Doe', + url: 'http://acme.org/~jd' + }, + license: 'dummy license' + // to be continued + } + const expected = new Models.Component( + Enums.ComponentType.Library, + 'bar', + { + author: 'Jane Doe', + description: `dummy lib ${salt}`, + externalReferences: new Models.ExternalReferenceRepository([`FAKE REFERENCES ${salt}`]), + licenses: new Models.LicenseRepository([`FAKE LICENSE ${salt}`]), + group: '@foo', + purl: new PackageURL('npm', '@foo', 'bar', `1.33.7-alpha.23.${salt}`, {}, undefined), + version: `1.33.7-alpha.23.${salt}` + } + ) + + test('makeComponent', () => { + const actual = sut.makeComponent(data) + assert.deepStrictEqual(actual, expected) + }) +}) diff --git a/tests/integration/JsonNormalize.test.js b/tests/integration/Serialize.JsonNormalize.test.js similarity index 100% rename from tests/integration/JsonNormalize.test.js rename to tests/integration/Serialize.JsonNormalize.test.js diff --git a/tests/integration/JsonSerialize.test.js b/tests/integration/Serialize.JsonSerialize.test.js similarity index 100% rename from tests/integration/JsonSerialize.test.js rename to tests/integration/Serialize.JsonSerialize.test.js diff --git a/tests/integration/XmlNormalize.test.js b/tests/integration/Serialize.XmlNormalize.test.js similarity index 100% rename from tests/integration/XmlNormalize.test.js rename to tests/integration/Serialize.XmlNormalize.test.js diff --git a/tests/integration/XmlSerialize.test.js b/tests/integration/Serialize.XmlSerialize.test.js similarity index 100% rename from tests/integration/XmlSerialize.test.js rename to tests/integration/Serialize.XmlSerialize.test.js diff --git a/tests/unit/Builders.FromPackageJson.ToolBuilder.spec.js b/tests/unit/Builders.FromPackageJson.ToolBuilder.spec.js new file mode 100644 index 000000000..4b00610ca --- /dev/null +++ b/tests/unit/Builders.FromPackageJson.ToolBuilder.spec.js @@ -0,0 +1,54 @@ +'use strict' +/*! +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. +*/ + +const assert = require('assert') +const { suite, test } = require('mocha') + +const { + Models, + Factories, + Builders: { FromPackageJson: { ToolBuilder } } +} = require('../../') + +suite('Builders.FromPackageJson.ToolBuilder', () => { + const salt = Math.random() + + const extRefFactory = new Factories.FromPackageJson.ExternalReferenceFactory() + extRefFactory.makeExternalReferences = () => [`FAKE REFERENCES ${salt}`] + + const sut = new ToolBuilder(extRefFactory) + + const data = { + name: '@foo/bar', + version: `1.33.7-alpha.23.${salt}` + // to be continued + } + const expected = new Models.Tool({ + vendor: '@foo', + name: 'bar', + version: `1.33.7-alpha.23.${salt}`, + externalReferences: new Models.ExternalReferenceRepository([`FAKE REFERENCES ${salt}`]) + }) + + test('makeTool', () => { + const actual = sut.makeTool(data) + assert.deepStrictEqual(actual, expected) + }) +}) diff --git a/tests/unit/Factories.FromPackageJson.ExternalReferenceFactory.spec.js b/tests/unit/Factories.FromPackageJson.ExternalReferenceFactory.spec.js new file mode 100644 index 000000000..c55f8b04d --- /dev/null +++ b/tests/unit/Factories.FromPackageJson.ExternalReferenceFactory.spec.js @@ -0,0 +1,166 @@ +'use strict' +/*! +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. +*/ + +const assert = require('assert') +const { suite, test } = require('mocha') + +const { + Enums: { ExternalReferenceType }, + Models: { ExternalReference }, + Factories: { FromPackageJson: { ExternalReferenceFactory } } +} = require('../../') + +suite('Factories.FromPackageJson.ExternalReferenceFactory', () => { + const sut = new ExternalReferenceFactory() + + suite('from "homepage"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar', + ExternalReferenceType.Website, + { comment: 'as detected from PackageJson property "homepage"' } + )] + const data = { homepage: 'https://foo.bar' } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { homepage: '' } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + test('is undefined', () => { + const data = { homepage: undefined } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) + + suite('from "bugs"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar', + ExternalReferenceType.IssueTracker, + { comment: 'as detected from PackageJson property "bugs"' } + )] + const data = { bugs: 'https://foo.bar' } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { bugs: '' } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + test('is undefined', () => { + const data = { bugs: undefined } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) + suite('from "bugs.url"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar', + ExternalReferenceType.IssueTracker, + { comment: 'as detected from PackageJson property "bugs.url"' } + )] + const data = { bugs: { url: 'https://foo.bar' } } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { bugs: { url: '' } } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + test('is undefined', () => { + const data = { bugs: { url: undefined } } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) + suite('from "repository"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar', + ExternalReferenceType.VCS, + { comment: 'as detected from PackageJson property "repository"' } + )] + const data = { repository: 'https://foo.bar' } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { repository: '' } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + test('is undefined', () => { + const data = { repository: undefined } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) + suite('from "repository.url"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar', + ExternalReferenceType.VCS, + { comment: 'as detected from PackageJson property "repository.url"' } + )] + const data = { repository: { url: 'https://foo.bar' } } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { repository: { url: '' } } + const repo = sut.makeExternalReferences(data) + assert.strictEqual(repo.length, 0) + }) + test('is undefined', () => { + const data = { repository: { url: undefined } } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) + suite('from "repository.directory"', () => { + test('is non-empty string', () => { + const expected = [new ExternalReference( + 'https://foo.bar#some/dir', + ExternalReferenceType.VCS, + { comment: 'as detected from PackageJson property "repository.url" and "repository.directory"' } + )] + const data = { repository: { url: 'https://foo.bar', directory: 'some/dir' } } + const actual = sut.makeExternalReferences(data) + assert.deepStrictEqual(actual, expected) + }) + test('is empty string', () => { + const data = { repository: { directory: '' } } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + test('is undefined', () => { + const data = { repository: { directory: undefined } } + const actual = sut.makeExternalReferences(data) + assert.strictEqual(actual.length, 0) + }) + }) +}) diff --git a/tsconfig.node.json b/tsconfig.node.json index 3da310704..04eb6fc78 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/tsconfig", "extends": "./tsconfig.json", - "files": ["src/_index.node.ts"], + "files": ["src/index.node.ts"], "compilerOptions": { "outDir": "./dist.node/" } diff --git a/tsconfig.web.json b/tsconfig.web.json index 69d221af1..417454f8b 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -1,5 +1,5 @@ { "$schema": "https://json.schemastore.org/tsconfig", "extends": "./tsconfig.json", - "files": ["src/_index.web.ts"] + "files": ["src/index.web.ts"] } diff --git a/webpack.config.js b/webpack.config.js index 874346acc..ea1b6f300 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -43,7 +43,7 @@ const configBase = { resolve: { extensions: ['.tsx', '.ts'] }, - entry: path.resolve(__dirname, 'src/_index.web.ts'), + entry: path.resolve(__dirname, 'src/index.web.ts'), output: { path: path.resolve(__dirname, 'dist.web'), // filename: '',