Skip to content

Commit a8f441d

Browse files
authored
feat: npmjs related symbols and parsing (#1246)
fixes #1247 ## Added * `factories.FromNodePackageJson.makeExternalReferences` supports "dist" field * New symbols under `utils.NpmJs` * `defaultRepoMatcher` * `parsePackageIntegrity` ---- TODO - [x] implementation - [x] tests --------- Signed-off-by: Jan Kowalleck <[email protected]>
1 parent d2abbb0 commit a8f441d

14 files changed

+360
-37
lines changed

HISTORY.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ All notable changes to this project will be documented in this file.
66

77
<!-- add unreleased items here -->
88

9+
* Added
10+
* `factories.FromNodePackageJson.makeExternalReferences()` supports "dist" field ([#1247] via [#1246])
11+
* New symbols under `utils.NpmjsUtility` (via [#1246])
12+
* `defaultRegistryMatcher`
13+
* `parsePackageIntegrity`
14+
15+
[#1246]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/1246
16+
[#1247]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/1247
17+
918
## 8.1.0 -- 2025-06-04
1019

1120
Support for _Node.js_ v24.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@
149149
"default": "./dist.node/types/index.js"
150150
},
151151
"./Utils": {
152-
"types": "./dist.d/utils/index.d.ts",
153-
"default": "./dist.node/utils/index.js"
152+
"types": "./dist.d/utils/index.node.d.ts",
153+
"default": "./dist.node/utils/index.node.js"
154154
},
155155
"./Validation": {
156156
"types": "./dist.d/validation/index.node.d.ts",

src/_helpers/packageJson.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,5 @@ export interface PackageJson {
6262
directory?: string
6363
}
6464
// ... to be continued
65+
dist?: any // see https://github.com/CycloneDX/cyclonedx-node-npm/issues/1300
6566
}

src/factories/fromNodePackageJson.node.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
2929
import type { PackageURL } from 'packageurl-js'
3030
import { PurlQualifierNames } from 'packageurl-js'
3131

32-
import {tryCanonicalizeGitUrl} from "../_helpers/gitUrl"
32+
import { tryCanonicalizeGitUrl } from "../_helpers/gitUrl"
3333
import { isNotUndefined } from '../_helpers/notUndefined'
3434
import type { PackageJson } from '../_helpers/packageJson'
3535
import { ExternalReferenceType } from '../enums/externalReferenceType'
36+
import { HashAlgorithm } from "../enums/hashAlogorithm";
3637
import type { Component } from '../models/component'
3738
import { ExternalReference } from '../models/externalReference'
39+
import { HashDictionary } from '../models/hash'
40+
import { defaultRegistryMatcher, parsePackageIntegrity } from '../utils/npmjsUtility.node'
3841
import { PackageUrlFactory as PlainPackageUrlFactory } from './packageUrl'
3942

4043
/**
@@ -47,6 +50,7 @@ export class ExternalReferenceFactory {
4750
try { refs.push(this.makeVcs(data)) } catch { /* pass */ }
4851
try { refs.push(this.makeHomepage(data)) } catch { /* pass */ }
4952
try { refs.push(this.makeIssueTracker(data)) } catch { /* pass */ }
53+
try { refs.push(this.makeDist(data)) } catch { /* pass */ }
5054

5155
return refs.filter(isNotUndefined)
5256
}
@@ -100,13 +104,32 @@ export class ExternalReferenceFactory {
100104
? new ExternalReference(url, ExternalReferenceType.IssueTracker, { comment })
101105
: undefined
102106
}
103-
}
104107

105-
/**
106-
* The default repository is `https://registry.npmjs.org`.
107-
* @see {@link https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#npm}
108-
*/
109-
const npmDefaultRepositoryMatcher = /^https?:\/\/registry\.npmjs\.org(:?\/|$)/
108+
makeDist(data: PackageJson): ExternalReference | undefined {
109+
// "dist" might be used in bundled dependencies' manifests.
110+
// docs: https://blog.npmjs.org/post/172999548390/new-pgp-machinery
111+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- acknowledged */
112+
const { tarball, integrity, shasum } = data.dist ?? {}
113+
if (typeof tarball === 'string') {
114+
const hashes = new HashDictionary()
115+
let comment = 'as detected from PackageJson property "dist.tarball"'
116+
if (typeof integrity === 'string') {
117+
try {
118+
// actually not the hash of the file, but more of an integrity-check -- lets use it anyway.
119+
// see https://blog.npmjs.org/post/172999548390/new-pgp-machinery
120+
hashes.set(...parsePackageIntegrity(integrity))
121+
comment += ' and property "dist.integrity"'
122+
} catch { /* pass */ }
123+
}
124+
if (typeof shasum === 'string' && shasum.length === 40) {
125+
hashes.set(HashAlgorithm["SHA-1"], shasum)
126+
comment += ' and property "dist.shasum"'
127+
}
128+
return new ExternalReference(tarball, ExternalReferenceType.Distribution, { hashes, comment })
129+
}
130+
return undefined
131+
}
132+
}
110133

111134
/**
112135
* Node-specific PackageUrlFactory.
@@ -134,13 +157,13 @@ export class PackageUrlFactory extends PlainPackageUrlFactory<'npm'> {
134157
* - "download_url" is stripped, if it is NPM's default registry ("registry.npmjs.org")
135158
* - "checksum" is stripped, unless a "download_url" or "vcs_url" is given.
136159
*/
137-
#finalizeQualifiers (purl: PackageURL): PackageURL {
160+
#finalizeQualifiers(purl: PackageURL): PackageURL {
138161
const qualifiers = new Map(Object.entries(purl.qualifiers ?? {}))
139162

140163
const downloadUrl = qualifiers.get(PurlQualifierNames.DownloadUrl)
141164
if (downloadUrl !== undefined) {
142165
qualifiers.delete(PurlQualifierNames.VcsUrl)
143-
if (npmDefaultRepositoryMatcher.test(downloadUrl)) {
166+
if (defaultRegistryMatcher.test(downloadUrl)) {
144167
qualifiers.delete(PurlQualifierNames.DownloadUrl)
145168
}
146169
}

src/index.common.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,4 @@ export * as Models from './models'
2222
export * as SPDX from './spdx'
2323
export * as Spec from './spec'
2424
export * as Types from './types'
25-
export * as Utils from './utils'
2625
// do not export the _helpers, they are for internal use only

src/index.node.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export * from './index.common'
2828
export * as Builders from './builders/index.node'
2929
export * as Factories from './factories/index.node'
3030
export * as Serialize from './serialize/index.node'
31+
export * as Utils from './utils/index.node'
3132
export * as Validation from './validation/index.node'
3233

3334
/**

src/index.web.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export * from './index.common'
2323

2424
export * as Factories from './factories/index.web'
2525
export * as Serialize from './serialize/index.web'
26+
export * as Utils from './utils/index.web'
2627
export * as Validation from './validation/index.web'
2728

2829
// endregion web-specifics
File renamed without changes.

src/utils/index.node.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
export * from './index.common'
21+
22+
// region node-specifics
23+
24+
export * as NpmjsUtility from './npmjsUtility.node'
25+
26+
// endregion node-specifics

src/utils/index.web.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
export * from './index.common'
21+
22+
// region web-specifics
23+
24+
// ... nothing yet
25+
26+
// endregion web-specifics

0 commit comments

Comments
 (0)