Skip to content

Commit

Permalink
feat: add function to return pacakge purl
Browse files Browse the repository at this point in the history
Signed-off-by: Brian DeHamer <bdehamer@github.com>
  • Loading branch information
bdehamer committed Nov 29, 2022
1 parent 103c0fd commit 262b573
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ included then the default is `latest`.

**Throws** if the package name is invalid, a dist-tag is invalid or a URL's protocol is not supported.

### var purl = npa.toPurl(*name*, *spec*)

Returns the purl (package URL) form of the given pacakge name/spec.

* *name* - The name of the module you want to install. For example: `foo` or `@bar/foo`.
* *spec* - The specifier indicating the semver-formatted version of the module. Something like:
`1.2` or `1.7.17`.

**Throws** if the package name is invalid, or the supplied version is not a valid semver value.

## RESULT OBJECT

The objects that are returned by npm-package-arg contain the following
Expand Down
24 changes: 24 additions & 0 deletions lib/npa.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'
module.exports = npa
module.exports.resolve = resolve
module.exports.toPurl = toPurl
module.exports.Result = Result

const url = require('url')
Expand Down Expand Up @@ -87,6 +88,22 @@ function resolve (name, spec, where, arg) {
}
}

function toPurl (arg, reg) {
const res = npa(arg)

if (res.type !== 'version') {
throw invalidPurlType(res.type, res.raw)
}

// URI-encode leading @ of scoped packages
let purl = 'pkg:npm/' + res.name.replace(/^@/, '%40') + '@' + res.rawSpec
if (reg) {
purl += '?repository_url=' + reg
}

return purl
}

function invalidPackageName (name, valid, raw) {
// eslint-disable-next-line max-len
const err = new Error(`Invalid package name "${name}" of package "${raw}": ${valid.errors.join('; ')}.`)
Expand All @@ -101,6 +118,13 @@ function invalidTagName (name, raw) {
return err
}

function invalidPurlType (type, raw) {
// eslint-disable-next-line max-len
const err = new Error(`Invalid type "${type}" of package "${raw}": Purl can only be generated from "tag" and "version" types.`)
err.code = 'EINVALIDPURLTYPE'
return err
}

function Result (opts) {
this.type = opts.type
this.registry = opts.registry
Expand Down
40 changes: 40 additions & 0 deletions test/purl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict'
var test = require('tap').test
var npa = require('..')

test('toPurl - valid', function (t) {
// Unscoped package
t.equal(npa.toPurl('foo@1.2.3'), 'pkg:npm/foo@1.2.3')

// Scoped package
t.equal(
npa.toPurl('@foo/bar@1.2.3-alpha.1'),
'pkg:npm/%40foo/bar@1.2.3-alpha.1')

// Non-default registry
t.equal(
npa.toPurl({ name: '@foo/bar', rawSpec: '1.0.0' }, 'npm.pkg.github.com'),
'pkg:npm/%40foo/bar@1.0.0?repository_url=npm.pkg.github.com'
)

t.end()
})

test('toPurl - invalid', function (t) {
// Invalid version
t.throws(() => npa.toPurl({ name: 'foo/bar', rawSpec: '1.0.0' }), {
code: 'EINVALIDPACKAGENAME',
})

// Invalid version
t.throws(() => npa.toPurl('foo@a.b.c'), {
code: 'EINVALIDPURLTYPE',
})

// Invalid type
t.throws(() => npa.toPurl('git+ssh://git@github.com/user/foo#1.2.3'), {
code: 'EINVALIDPURLTYPE',
})

t.end()
})

0 comments on commit 262b573

Please sign in to comment.