Changing front

This commit is contained in:
2023-01-16 17:44:37 +01:00
parent 0b8a93b256
commit 4fe4be7730
48586 changed files with 4725790 additions and 17464 deletions

16
front/app/node_modules/npm-pick-manifest/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,16 @@
ISC License
Copyright (c) npm, Inc.
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
USE OR PERFORMANCE OF THIS SOFTWARE.

157
front/app/node_modules/npm-pick-manifest/README.md generated vendored Normal file
View File

@@ -0,0 +1,157 @@
# npm-pick-manifest [![npm version](https://img.shields.io/npm/v/npm-pick-manifest.svg)](https://npm.im/npm-pick-manifest) [![license](https://img.shields.io/npm/l/npm-pick-manifest.svg)](https://npm.im/npm-pick-manifest) [![Travis](https://img.shields.io/travis/npm/npm-pick-manifest.svg)](https://travis-ci.org/npm/npm-pick-manifest) [![Coverage Status](https://coveralls.io/repos/github/npm/npm-pick-manifest/badge.svg?branch=latest)](https://coveralls.io/github/npm/npm-pick-manifest?branch=latest)
[`npm-pick-manifest`](https://github.com/npm/npm-pick-manifest) is a standalone
implementation of [npm](https://npmjs.com)'s semver range resolution algorithm.
## Install
`$ npm install --save npm-pick-manifest`
## Table of Contents
* [Example](#example)
* [Features](#features)
* [API](#api)
* [`pickManifest()`](#pick-manifest)
### Example
```javascript
const pickManifest = require('npm-pick-manifest')
fetch('https://registry.npmjs.org/npm-pick-manifest').then(res => {
return res.json()
}).then(packument => {
return pickManifest(packument, '^1.0.0')
}) // get same manifest as npm would get if you `npm i npm-pick-manifest@^1.0.0`
```
### Features
* Uses npm's exact [semver resolution algorithm](http://npm.im/semver).
* Supports ranges, tags, and versions.
* Prefers non-deprecated versions to deprecated versions.
* Prefers versions whose `engines` requirements are satisfied over those
that will raise a warning or error at install time.
### API
#### <a name="pick-manifest"></a> `> pickManifest(packument, selector, [opts]) -> manifest`
Returns the manifest that best matches `selector`, or throws an error.
Packuments are anything returned by metadata URLs from the npm registry. That
is, they're objects with the following shape (only fields used by
`npm-pick-manifest` included):
```javascript
{
name: 'some-package',
'dist-tags': {
foo: '1.0.1'
},
versions: {
'1.0.0': { version: '1.0.0' },
'1.0.1': { version: '1.0.1' },
'1.0.2': { version: '1.0.2' },
'2.0.0': { version: '2.0.0' }
}
}
```
The algorithm will follow npm's algorithm for semver resolution, and only
`tag`, `range`, and `version` selectors are supported.
The function will throw `ETARGET` if there was no matching manifest, and
`ENOVERSIONS` if the packument object has no valid versions in `versions`.
If the only matching manifest is included in a `policyRestrictions` section
of the packument, then an `E403` is raised.
#### <a name="pick-manifest-options"></a> Options
All options are optional.
* `includeStaged` - Boolean, default `false`. Include manifests in the
`stagedVersions.versions` set, to support installing [staged
packages](https://github.com/npm/rfcs/pull/92) when appropriate. Note
that staged packages are always treated as lower priority than actual
publishes, even when `includeStaged` is set.
* `defaultTag` - String, default `'latest'`. The default `dist-tag` to
install when no specifier is provided. Note that the version indicated
by this specifier will be given top priority if it matches a supplied
semver range.
* `before` - String, Date, or Number, default `null`. This is passed to
`new Date()`, so anything that works there will be valid. Do not
consider _any_ manifests that were published after the date indicated.
Note that this is only relevant when the packument includes a `time`
field listing the publish date of all the packages.
* `nodeVersion` - String, default `process.version`. The Node.js version
to use when checking manifests for `engines` requirement satisfaction.
* `npmVersion` - String, default `null`. The npm version to use when
checking manifest for `engines` requirement satisfaction. (If `null`,
then this particular check is skipped.)
* `avoid` - String, default `null`. A SemVer range of
versions that should be avoided. An avoided version MAY be selected if
there is no other option, so when using this for version selection ensure
that you check the result against the range to see if there was no
alternative available.
* `avoidStrict` Boolean, default `false`. If set to true, then
`pickManifest` will never return a version in the `avoid` range. If the
only available version in the `wanted` range is a version that should be
avoided, then it will return a version _outside_ the `wanted` range,
preferring to do so without making a SemVer-major jump, if possible. If
there are no versions outside the `avoid` range, then throw an
`ETARGET` error. It does this by calling pickManifest first with the
`wanted` range, then with a `^` affixed to the version returned by the
`wanted` range, and then with a `*` version range, and throwing if
nothing could be found to satisfy the avoidance request.
Return value is the manifest as it exists in the packument, possibly
decorated with the following boolean flags:
* `_shouldAvoid` The version is in the `avoid` range. Watch out!
* `_outsideDependencyRange` The version is outside the `wanted` range,
because `avoidStrict: true` was set.
* `_isSemVerMajor` The `_outsideDependencyRange` result is a SemVer-major
step up from the version returned by the `wanted` range.
### Algorithm
1. Create list of all versions in `versions`,
`policyRestrictions.versions`, and (if `includeStaged` is set)
`stagedVersions.versions`.
2. If a `dist-tag` is requested,
1. If the manifest is not after the specified `before` date, then
select that from the set.
2. If the manifest is after the specified `before` date, then re-start
the selection looking for the highest SemVer range that is equal to
or less than the `dist-tag` target.
3. If a specific version is requested,
1. If the manifest is not after the specified `before` date, then
select the specified manifest.
2. If the manifest is after the specified `before` date, then raise
`ETARGET` error. (NB: this is a breaking change from v5, where a
specified version would override the `before` setting.)
4. (At this point we know a range is requested.)
5. If the `defaultTag` refers to a `dist-tag` that satisfies the range (or
if the range is `'*'` or `''`), and the manifest is published before the
`before` setting, then select that manifest.
6. If nothing is yet selected, sort by the following heuristics in order,
and select the top item:
1. Prioritize versions that are not in the `avoid` range over those
that are.
2. Prioritize versions that are not in `policyRestrictions` over those
that are.
3. Prioritize published versions over staged versions.
4. Prioritize versions that are not deprecated, and which have a
satisfied engines requirement, over those that are either deprecated
or have an engines mismatch.
5. Prioritize versions that have a satisfied engines requirement over
those that do not.
6. Prioritize versions that are not are not deprecated (but have a
mismatched engines requirement) over those that are deprecated.
7. Prioritize higher SemVer precedence over lower SemVer precedence.
7. If no manifest was selected, raise an `ETARGET` error.
8. If the selected item is in the `policyRestrictions.versions` list, raise
an `E403` error.
9. Return the selected manifest.

218
front/app/node_modules/npm-pick-manifest/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,218 @@
'use strict'
const npa = require('npm-package-arg')
const semver = require('semver')
const { checkEngine } = require('npm-install-checks')
const normalizeBin = require('npm-normalize-package-bin')
const engineOk = (manifest, npmVersion, nodeVersion) => {
try {
checkEngine(manifest, npmVersion, nodeVersion)
return true
} catch (_) {
return false
}
}
const isBefore = (verTimes, ver, time) =>
!verTimes || !verTimes[ver] || Date.parse(verTimes[ver]) <= time
const avoidSemverOpt = { includePrerelease: true, loose: true }
const shouldAvoid = (ver, avoid) =>
avoid && semver.satisfies(ver, avoid, avoidSemverOpt)
const decorateAvoid = (result, avoid) =>
result && shouldAvoid(result.version, avoid)
? { ...result, _shouldAvoid: true }
: result
const pickManifest = (packument, wanted, opts) => {
const {
defaultTag = 'latest',
before = null,
nodeVersion = process.version,
npmVersion = null,
includeStaged = false,
avoid = null,
avoidStrict = false,
} = opts
const { name, time: verTimes } = packument
const versions = packument.versions || {}
if (avoidStrict) {
const looseOpts = {
...opts,
avoidStrict: false,
}
const result = pickManifest(packument, wanted, looseOpts)
if (!result || !result._shouldAvoid) {
return result
}
const caret = pickManifest(packument, `^${result.version}`, looseOpts)
if (!caret || !caret._shouldAvoid) {
return {
...caret,
_outsideDependencyRange: true,
_isSemVerMajor: false,
}
}
const star = pickManifest(packument, '*', looseOpts)
if (!star || !star._shouldAvoid) {
return {
...star,
_outsideDependencyRange: true,
_isSemVerMajor: true,
}
}
throw Object.assign(new Error(`No avoidable versions for ${name}`), {
code: 'ETARGET',
name,
wanted,
avoid,
before,
versions: Object.keys(versions),
})
}
const staged = (includeStaged && packument.stagedVersions &&
packument.stagedVersions.versions) || {}
const restricted = (packument.policyRestrictions &&
packument.policyRestrictions.versions) || {}
const time = before && verTimes ? +(new Date(before)) : Infinity
const spec = npa.resolve(name, wanted || defaultTag)
const type = spec.type
const distTags = packument['dist-tags'] || {}
if (type !== 'tag' && type !== 'version' && type !== 'range') {
throw new Error('Only tag, version, and range are supported')
}
// if the type is 'tag', and not just the implicit default, then it must
// be that exactly, or nothing else will do.
if (wanted && type === 'tag') {
const ver = distTags[wanted]
// if the version in the dist-tags is before the before date, then
// we use that. Otherwise, we get the highest precedence version
// prior to the dist-tag.
if (isBefore(verTimes, ver, time)) {
return decorateAvoid(versions[ver] || staged[ver] || restricted[ver], avoid)
} else {
return pickManifest(packument, `<=${ver}`, opts)
}
}
// similarly, if a specific version, then only that version will do
if (wanted && type === 'version') {
const ver = semver.clean(wanted, { loose: true })
const mani = versions[ver] || staged[ver] || restricted[ver]
return isBefore(verTimes, ver, time) ? decorateAvoid(mani, avoid) : null
}
// ok, sort based on our heuristics, and pick the best fit
const range = type === 'range' ? wanted : '*'
// if the range is *, then we prefer the 'latest' if available
// but skip this if it should be avoided, in that case we have
// to try a little harder.
const defaultVer = distTags[defaultTag]
if (defaultVer &&
(range === '*' || semver.satisfies(defaultVer, range, { loose: true })) &&
!shouldAvoid(defaultVer, avoid)) {
const mani = versions[defaultVer]
if (mani && isBefore(verTimes, defaultVer, time)) {
return mani
}
}
// ok, actually have to sort the list and take the winner
const allEntries = Object.entries(versions)
.concat(Object.entries(staged))
.concat(Object.entries(restricted))
.filter(([ver, mani]) => isBefore(verTimes, ver, time))
if (!allEntries.length) {
throw Object.assign(new Error(`No versions available for ${name}`), {
code: 'ENOVERSIONS',
name,
type,
wanted,
before,
versions: Object.keys(versions),
})
}
const sortSemverOpt = { loose: true }
const entries = allEntries.filter(([ver, mani]) =>
semver.satisfies(ver, range, { loose: true }))
.sort((a, b) => {
const [vera, mania] = a
const [verb, manib] = b
const notavoida = !shouldAvoid(vera, avoid)
const notavoidb = !shouldAvoid(verb, avoid)
const notrestra = !restricted[a]
const notrestrb = !restricted[b]
const notstagea = !staged[a]
const notstageb = !staged[b]
const notdepra = !mania.deprecated
const notdeprb = !manib.deprecated
const enginea = engineOk(mania, npmVersion, nodeVersion)
const engineb = engineOk(manib, npmVersion, nodeVersion)
// sort by:
// - not an avoided version
// - not restricted
// - not staged
// - not deprecated and engine ok
// - engine ok
// - not deprecated
// - semver
return (notavoidb - notavoida) ||
(notrestrb - notrestra) ||
(notstageb - notstagea) ||
((notdeprb && engineb) - (notdepra && enginea)) ||
(engineb - enginea) ||
(notdeprb - notdepra) ||
semver.rcompare(vera, verb, sortSemverOpt)
})
return decorateAvoid(entries[0] && entries[0][1], avoid)
}
module.exports = (packument, wanted, opts = {}) => {
const mani = pickManifest(packument, wanted, opts)
const picked = mani && normalizeBin(mani)
const policyRestrictions = packument.policyRestrictions
const restricted = (policyRestrictions && policyRestrictions.versions) || {}
if (picked && !restricted[picked.version]) {
return picked
}
const { before = null, defaultTag = 'latest' } = opts
const bstr = before ? new Date(before).toLocaleString() : ''
const { name } = packument
const pckg = `${name}@${wanted}` +
(before ? ` with a date before ${bstr}` : '')
const isForbidden = picked && !!restricted[picked.version]
const polMsg = isForbidden ? policyRestrictions.message : ''
const msg = !isForbidden ? `No matching version found for ${pckg}.`
: `Could not download ${pckg} due to policy violations:\n${polMsg}`
const code = isForbidden ? 'E403' : 'ETARGET'
throw Object.assign(new Error(msg), {
code,
type: npa.resolve(packument.name, wanted).type,
wanted,
versions: Object.keys(packument.versions),
name,
distTags: packument['dist-tags'],
defaultTag,
})
}

View File

@@ -0,0 +1,13 @@
Copyright (c) 2015, Rebecca Turner
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,133 @@
# hosted-git-info
This will let you identify and transform various git hosts URLs between
protocols. It also can tell you what the URL is for the raw path for
particular file for direct access without git.
## Example
```javascript
const hostedGitInfo = require("hosted-git-info")
const info = hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git", opts)
/* info looks like:
{
type: "github",
domain: "github.com",
user: "npm",
project: "hosted-git-info"
}
*/
```
If the URL can't be matched with a git host, `null` will be returned. We
can match git, ssh and https urls. Additionally, we can match ssh connect
strings (`git@github.com:npm/hosted-git-info`) and shortcuts (eg,
`github:npm/hosted-git-info`). GitHub specifically, is detected in the case
of a third, unprefixed, form: `npm/hosted-git-info`.
If it does match, the returned object has properties of:
* info.type -- The short name of the service
* info.domain -- The domain for git protocol use
* info.user -- The name of the user/org on the git host
* info.project -- The name of the project on the git host
## Version Contract
The major version will be bumped any time…
* The constructor stops accepting URLs that it previously accepted.
* A method is removed.
* A method can no longer accept the number and type of arguments it previously accepted.
* A method can return a different type than it currently returns.
Implications:
* I do not consider the specific format of the urls returned from, say
`.https()` to be a part of the contract. The contract is that it will
return a string that can be used to fetch the repo via HTTPS. But what
that string looks like, specifically, can change.
* Dropping support for a hosted git provider would constitute a breaking
change.
## Usage
### const info = hostedGitInfo.fromUrl(gitSpecifier[, options])
* *gitSpecifer* is a URL of a git repository or a SCP-style specifier of one.
* *options* is an optional object. It can have the following properties:
* *noCommittish* — If true then committishes won't be included in generated URLs.
* *noGitPlus* — If true then `git+` won't be prefixed on URLs.
## Methods
All of the methods take the same options as the `fromUrl` factory. Options
provided to a method override those provided to the constructor.
* info.file(path, opts)
Given the path of a file relative to the repository, returns a URL for
directly fetching it from the githost. If no committish was set then
`HEAD` will be used as the default.
For example `hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git#v1.0.0").file("package.json")`
would return `https://raw.githubusercontent.com/npm/hosted-git-info/v1.0.0/package.json`
* info.shortcut(opts)
eg, `github:npm/hosted-git-info`
* info.browse(path, fragment, opts)
eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0`,
`https://github.com/npm/hosted-git-info/tree/v1.2.0/package.json`,
`https://github.com/npm/hosted-git-info/tree/v1.2.0/REAMDE.md#supported-hosts`
* info.bugs(opts)
eg, `https://github.com/npm/hosted-git-info/issues`
* info.docs(opts)
eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0#readme`
* info.https(opts)
eg, `git+https://github.com/npm/hosted-git-info.git`
* info.sshurl(opts)
eg, `git+ssh://git@github.com/npm/hosted-git-info.git`
* info.ssh(opts)
eg, `git@github.com:npm/hosted-git-info.git`
* info.path(opts)
eg, `npm/hosted-git-info`
* info.tarball(opts)
eg, `https://github.com/npm/hosted-git-info/archive/v1.2.0.tar.gz`
* info.getDefaultRepresentation()
Returns the default output type. The default output type is based on the
string you passed in to be parsed
* info.toString(opts)
Uses the getDefaultRepresentation to call one of the other methods to get a URL for
this resource. As such `hostedGitInfo.fromUrl(url).toString()` will give
you a normalized version of the URL that still uses the same protocol.
Shortcuts will still be returned as shortcuts, but the special case github
form of `org/project` will be normalized to `github:org/project`.
SSH connect strings will be normalized into `git+ssh` URLs.
## Supported hosts
Currently this supports GitHub (including Gists), Bitbucket, GitLab and Sourcehut.
Pull requests for additional hosts welcome.

View File

@@ -0,0 +1,122 @@
'use strict'
const parseUrl = require('./parse-url')
// look for github shorthand inputs, such as npm/cli
const isGitHubShorthand = (arg) => {
// it cannot contain whitespace before the first #
// it cannot start with a / because that's probably an absolute file path
// but it must include a slash since repos are username/repository
// it cannot start with a . because that's probably a relative file path
// it cannot start with an @ because that's a scoped package if it passes the other tests
// it cannot contain a : before a # because that tells us that there's a protocol
// a second / may not exist before a #
const firstHash = arg.indexOf('#')
const firstSlash = arg.indexOf('/')
const secondSlash = arg.indexOf('/', firstSlash + 1)
const firstColon = arg.indexOf(':')
const firstSpace = /\s/.exec(arg)
const firstAt = arg.indexOf('@')
const spaceOnlyAfterHash = !firstSpace || (firstHash > -1 && firstSpace.index > firstHash)
const atOnlyAfterHash = firstAt === -1 || (firstHash > -1 && firstAt > firstHash)
const colonOnlyAfterHash = firstColon === -1 || (firstHash > -1 && firstColon > firstHash)
const secondSlashOnlyAfterHash = secondSlash === -1 || (firstHash > -1 && secondSlash > firstHash)
const hasSlash = firstSlash > 0
// if a # is found, what we really want to know is that the character
// immediately before # is not a /
const doesNotEndWithSlash = firstHash > -1 ? arg[firstHash - 1] !== '/' : !arg.endsWith('/')
const doesNotStartWithDot = !arg.startsWith('.')
return spaceOnlyAfterHash && hasSlash && doesNotEndWithSlash &&
doesNotStartWithDot && atOnlyAfterHash && colonOnlyAfterHash &&
secondSlashOnlyAfterHash
}
module.exports = (giturl, opts, { gitHosts, protocols }) => {
if (!giturl) {
return
}
const correctedUrl = isGitHubShorthand(giturl) ? `github:${giturl}` : giturl
const parsed = parseUrl(correctedUrl, protocols)
if (!parsed) {
return
}
const gitHostShortcut = gitHosts.byShortcut[parsed.protocol]
const gitHostDomain = gitHosts.byDomain[parsed.hostname.startsWith('www.')
? parsed.hostname.slice(4)
: parsed.hostname]
const gitHostName = gitHostShortcut || gitHostDomain
if (!gitHostName) {
return
}
const gitHostInfo = gitHosts[gitHostShortcut || gitHostDomain]
let auth = null
if (protocols[parsed.protocol]?.auth && (parsed.username || parsed.password)) {
auth = `${parsed.username}${parsed.password ? ':' + parsed.password : ''}`
}
let committish = null
let user = null
let project = null
let defaultRepresentation = null
try {
if (gitHostShortcut) {
let pathname = parsed.pathname.startsWith('/') ? parsed.pathname.slice(1) : parsed.pathname
const firstAt = pathname.indexOf('@')
// we ignore auth for shortcuts, so just trim it out
if (firstAt > -1) {
pathname = pathname.slice(firstAt + 1)
}
const lastSlash = pathname.lastIndexOf('/')
if (lastSlash > -1) {
user = decodeURIComponent(pathname.slice(0, lastSlash))
// we want nulls only, never empty strings
if (!user) {
user = null
}
project = decodeURIComponent(pathname.slice(lastSlash + 1))
} else {
project = decodeURIComponent(pathname)
}
if (project.endsWith('.git')) {
project = project.slice(0, -4)
}
if (parsed.hash) {
committish = decodeURIComponent(parsed.hash.slice(1))
}
defaultRepresentation = 'shortcut'
} else {
if (!gitHostInfo.protocols.includes(parsed.protocol)) {
return
}
const segments = gitHostInfo.extract(parsed)
if (!segments) {
return
}
user = segments.user && decodeURIComponent(segments.user)
project = decodeURIComponent(segments.project)
committish = decodeURIComponent(segments.committish)
defaultRepresentation = protocols[parsed.protocol]?.name || parsed.protocol.slice(0, -1)
}
} catch (err) {
/* istanbul ignore else */
if (err instanceof URIError) {
return
} else {
throw err
}
}
return [gitHostName, user, auth, project, committish, defaultRepresentation, opts]
}

View File

@@ -0,0 +1,228 @@
/* eslint-disable max-len */
'use strict'
const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : ''
const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : ''
const formatHashFragment = (f) => f.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
const defaults = {
sshtemplate: ({ domain, user, project, committish }) =>
`git@${domain}:${user}/${project}.git${maybeJoin('#', committish)}`,
sshurltemplate: ({ domain, user, project, committish }) =>
`git+ssh://git@${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
edittemplate: ({ domain, user, project, committish, editpath, path }) =>
`https://${domain}/${user}/${project}${maybeJoin('/', editpath, '/', maybeEncode(committish || 'HEAD'), '/', path)}`,
browsetemplate: ({ domain, user, project, committish, treepath }) =>
`https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`,
browsetreetemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) =>
`https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`,
browseblobtemplate: ({ domain, user, project, committish, blobpath, path, fragment, hashformat }) =>
`https://${domain}/${user}/${project}/${blobpath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`,
docstemplate: ({ domain, user, project, treepath, committish }) =>
`https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`,
httpstemplate: ({ auth, domain, user, project, committish }) =>
`git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
filetemplate: ({ domain, user, project, committish, path }) =>
`https://${domain}/${user}/${project}/raw/${maybeEncode(committish || 'HEAD')}/${path}`,
shortcuttemplate: ({ type, user, project, committish }) =>
`${type}:${user}/${project}${maybeJoin('#', committish)}`,
pathtemplate: ({ user, project, committish }) =>
`${user}/${project}${maybeJoin('#', committish)}`,
bugstemplate: ({ domain, user, project }) =>
`https://${domain}/${user}/${project}/issues`,
hashformat: formatHashFragment,
}
const hosts = {}
hosts.github = {
// First two are insecure and generally shouldn't be used any more, but
// they are still supported.
protocols: ['git:', 'http:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'github.com',
treepath: 'tree',
blobpath: 'blob',
editpath: 'edit',
filetemplate: ({ auth, user, project, committish, path }) =>
`https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish || 'HEAD')}/${path}`,
gittemplate: ({ auth, domain, user, project, committish }) =>
`git://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
tarballtemplate: ({ domain, user, project, committish }) =>
`https://codeload.${domain}/${user}/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`,
extract: (url) => {
let [, user, project, type, committish] = url.pathname.split('/', 5)
if (type && type !== 'tree') {
return
}
if (!type) {
committish = url.hash.slice(1)
}
if (project && project.endsWith('.git')) {
project = project.slice(0, -4)
}
if (!user || !project) {
return
}
return { user, project, committish }
},
}
hosts.bitbucket = {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'bitbucket.org',
treepath: 'src',
blobpath: 'src',
editpath: '?mode=edit',
edittemplate: ({ domain, user, project, committish, treepath, path, editpath }) =>
`https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish || 'HEAD'), '/', path, editpath)}`,
tarballtemplate: ({ domain, user, project, committish }) =>
`https://${domain}/${user}/${project}/get/${maybeEncode(committish || 'HEAD')}.tar.gz`,
extract: (url) => {
let [, user, project, aux] = url.pathname.split('/', 4)
if (['get'].includes(aux)) {
return
}
if (project && project.endsWith('.git')) {
project = project.slice(0, -4)
}
if (!user || !project) {
return
}
return { user, project, committish: url.hash.slice(1) }
},
}
hosts.gitlab = {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gitlab.com',
treepath: 'tree',
blobpath: 'tree',
editpath: '-/edit',
httpstemplate: ({ auth, domain, user, project, committish }) =>
`git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
tarballtemplate: ({ domain, user, project, committish }) =>
`https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish || 'HEAD')}`,
extract: (url) => {
const path = url.pathname.slice(1)
if (path.includes('/-/') || path.includes('/archive.tar.gz')) {
return
}
const segments = path.split('/')
let project = segments.pop()
if (project.endsWith('.git')) {
project = project.slice(0, -4)
}
const user = segments.join('/')
if (!user || !project) {
return
}
return { user, project, committish: url.hash.slice(1) }
},
}
hosts.gist = {
protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gist.github.com',
editpath: 'edit',
sshtemplate: ({ domain, project, committish }) =>
`git@${domain}:${project}.git${maybeJoin('#', committish)}`,
sshurltemplate: ({ domain, project, committish }) =>
`git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`,
edittemplate: ({ domain, user, project, committish, editpath }) =>
`https://${domain}/${user}/${project}${maybeJoin('/', maybeEncode(committish))}/${editpath}`,
browsetemplate: ({ domain, project, committish }) =>
`https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
browsetreetemplate: ({ domain, project, committish, path, hashformat }) =>
`https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`,
browseblobtemplate: ({ domain, project, committish, path, hashformat }) =>
`https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`,
docstemplate: ({ domain, project, committish }) =>
`https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
httpstemplate: ({ domain, project, committish }) =>
`git+https://${domain}/${project}.git${maybeJoin('#', committish)}`,
filetemplate: ({ user, project, committish, path }) =>
`https://gist.githubusercontent.com/${user}/${project}/raw${maybeJoin('/', maybeEncode(committish))}/${path}`,
shortcuttemplate: ({ type, project, committish }) =>
`${type}:${project}${maybeJoin('#', committish)}`,
pathtemplate: ({ project, committish }) =>
`${project}${maybeJoin('#', committish)}`,
bugstemplate: ({ domain, project }) =>
`https://${domain}/${project}`,
gittemplate: ({ domain, project, committish }) =>
`git://${domain}/${project}.git${maybeJoin('#', committish)}`,
tarballtemplate: ({ project, committish }) =>
`https://codeload.github.com/gist/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`,
extract: (url) => {
let [, user, project, aux] = url.pathname.split('/', 4)
if (aux === 'raw') {
return
}
if (!project) {
if (!user) {
return
}
project = user
user = null
}
if (project.endsWith('.git')) {
project = project.slice(0, -4)
}
return { user, project, committish: url.hash.slice(1) }
},
hashformat: function (fragment) {
return fragment && 'file-' + formatHashFragment(fragment)
},
}
hosts.sourcehut = {
protocols: ['git+ssh:', 'https:'],
domain: 'git.sr.ht',
treepath: 'tree',
blobpath: 'tree',
filetemplate: ({ domain, user, project, committish, path }) =>
`https://${domain}/${user}/${project}/blob/${maybeEncode(committish) || 'HEAD'}/${path}`,
httpstemplate: ({ domain, user, project, committish }) =>
`https://${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
tarballtemplate: ({ domain, user, project, committish }) =>
`https://${domain}/${user}/${project}/archive/${maybeEncode(committish) || 'HEAD'}.tar.gz`,
bugstemplate: ({ user, project }) =>
`https://todo.sr.ht/${user}/${project}`,
extract: (url) => {
let [, user, project, aux] = url.pathname.split('/', 4)
// tarball url
if (['archive'].includes(aux)) {
return
}
if (project && project.endsWith('.git')) {
project = project.slice(0, -4)
}
if (!user || !project) {
return
}
return { user, project, committish: url.hash.slice(1) }
},
}
for (const [name, host] of Object.entries(hosts)) {
hosts[name] = Object.assign({}, defaults, host)
}
module.exports = hosts

View File

@@ -0,0 +1,179 @@
'use strict'
const LRU = require('lru-cache')
const hosts = require('./hosts.js')
const fromUrl = require('./from-url.js')
const parseUrl = require('./parse-url.js')
const cache = new LRU({ max: 1000 })
class GitHost {
constructor (type, user, auth, project, committish, defaultRepresentation, opts = {}) {
Object.assign(this, GitHost.#gitHosts[type], {
type,
user,
auth,
project,
committish,
default: defaultRepresentation,
opts,
})
}
static #gitHosts = { byShortcut: {}, byDomain: {} }
static #protocols = {
'git+ssh:': { name: 'sshurl' },
'ssh:': { name: 'sshurl' },
'git+https:': { name: 'https', auth: true },
'git:': { auth: true },
'http:': { auth: true },
'https:': { auth: true },
'git+http:': { auth: true },
}
static addHost (name, host) {
GitHost.#gitHosts[name] = host
GitHost.#gitHosts.byDomain[host.domain] = name
GitHost.#gitHosts.byShortcut[`${name}:`] = name
GitHost.#protocols[`${name}:`] = { name }
}
static fromUrl (giturl, opts) {
if (typeof giturl !== 'string') {
return
}
const key = giturl + JSON.stringify(opts || {})
if (!cache.has(key)) {
const hostArgs = fromUrl(giturl, opts, {
gitHosts: GitHost.#gitHosts,
protocols: GitHost.#protocols,
})
cache.set(key, hostArgs ? new GitHost(...hostArgs) : undefined)
}
return cache.get(key)
}
static parseUrl (url) {
return parseUrl(url)
}
#fill (template, opts) {
if (typeof template !== 'function') {
return null
}
const options = { ...this, ...this.opts, ...opts }
// the path should always be set so we don't end up with 'undefined' in urls
if (!options.path) {
options.path = ''
}
// template functions will insert the leading slash themselves
if (options.path.startsWith('/')) {
options.path = options.path.slice(1)
}
if (options.noCommittish) {
options.committish = null
}
const result = template(options)
return options.noGitPlus && result.startsWith('git+') ? result.slice(4) : result
}
hash () {
return this.committish ? `#${this.committish}` : ''
}
ssh (opts) {
return this.#fill(this.sshtemplate, opts)
}
sshurl (opts) {
return this.#fill(this.sshurltemplate, opts)
}
browse (path, ...args) {
// not a string, treat path as opts
if (typeof path !== 'string') {
return this.#fill(this.browsetemplate, path)
}
if (typeof args[0] !== 'string') {
return this.#fill(this.browsetreetemplate, { ...args[0], path })
}
return this.#fill(this.browsetreetemplate, { ...args[1], fragment: args[0], path })
}
// If the path is known to be a file, then browseFile should be used. For some hosts
// the url is the same as browse, but for others like GitHub a file can use both `/tree/`
// and `/blob/` in the path. When using a default committish of `HEAD` then the `/tree/`
// path will redirect to a specific commit. Using the `/blob/` path avoids this and
// does not redirect to a different commit.
browseFile (path, ...args) {
if (typeof args[0] !== 'string') {
return this.#fill(this.browseblobtemplate, { ...args[0], path })
}
return this.#fill(this.browseblobtemplate, { ...args[1], fragment: args[0], path })
}
docs (opts) {
return this.#fill(this.docstemplate, opts)
}
bugs (opts) {
return this.#fill(this.bugstemplate, opts)
}
https (opts) {
return this.#fill(this.httpstemplate, opts)
}
git (opts) {
return this.#fill(this.gittemplate, opts)
}
shortcut (opts) {
return this.#fill(this.shortcuttemplate, opts)
}
path (opts) {
return this.#fill(this.pathtemplate, opts)
}
tarball (opts) {
return this.#fill(this.tarballtemplate, { ...opts, noCommittish: false })
}
file (path, opts) {
return this.#fill(this.filetemplate, { ...opts, path })
}
edit (path, opts) {
return this.#fill(this.edittemplate, { ...opts, path })
}
getDefaultRepresentation () {
return this.default
}
toString (opts) {
if (this.default && typeof this[this.default] === 'function') {
return this[this.default](opts)
}
return this.sshurl(opts)
}
}
for (const [name, host] of Object.entries(hosts)) {
GitHost.addHost(name, host)
}
module.exports = GitHost

View File

@@ -0,0 +1,78 @@
const url = require('url')
const lastIndexOfBefore = (str, char, beforeChar) => {
const startPosition = str.indexOf(beforeChar)
return str.lastIndexOf(char, startPosition > -1 ? startPosition : Infinity)
}
const safeUrl = (u) => {
try {
return new url.URL(u)
} catch {
// this fn should never throw
}
}
// accepts input like git:github.com:user/repo and inserts the // after the first :
const correctProtocol = (arg, protocols) => {
const firstColon = arg.indexOf(':')
const proto = arg.slice(0, firstColon + 1)
if (Object.prototype.hasOwnProperty.call(protocols, proto)) {
return arg
}
const firstAt = arg.indexOf('@')
if (firstAt > -1) {
if (firstAt > firstColon) {
return `git+ssh://${arg}`
} else {
return arg
}
}
const doubleSlash = arg.indexOf('//')
if (doubleSlash === firstColon + 1) {
return arg
}
return `${arg.slice(0, firstColon + 1)}//${arg.slice(firstColon + 1)}`
}
// attempt to correct an scp style url so that it will parse with `new URL()`
const correctUrl = (giturl) => {
// ignore @ that come after the first hash since the denotes the start
// of a committish which can contain @ characters
const firstAt = lastIndexOfBefore(giturl, '@', '#')
// ignore colons that come after the hash since that could include colons such as:
// git@github.com:user/package-2#semver:^1.0.0
const lastColonBeforeHash = lastIndexOfBefore(giturl, ':', '#')
if (lastColonBeforeHash > firstAt) {
// the last : comes after the first @ (or there is no @)
// like it would in:
// proto://hostname.com:user/repo
// username@hostname.com:user/repo
// :password@hostname.com:user/repo
// username:password@hostname.com:user/repo
// proto://username@hostname.com:user/repo
// proto://:password@hostname.com:user/repo
// proto://username:password@hostname.com:user/repo
// then we replace the last : with a / to create a valid path
giturl = giturl.slice(0, lastColonBeforeHash) + '/' + giturl.slice(lastColonBeforeHash + 1)
}
if (lastIndexOfBefore(giturl, ':', '#') === -1 && giturl.indexOf('//') === -1) {
// we have no : at all
// as it would be in:
// username@hostname.com/user/repo
// then we prepend a protocol
giturl = `git+ssh://${giturl}`
}
return giturl
}
module.exports = (giturl, protocols) => {
const withProtocol = protocols ? correctProtocol(giturl, protocols) : giturl
return safeUrl(withProtocol) || safeUrl(correctUrl(withProtocol))
}

View File

@@ -0,0 +1,59 @@
{
"name": "hosted-git-info",
"version": "6.1.1",
"description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab",
"main": "./lib/index.js",
"repository": {
"type": "git",
"url": "https://github.com/npm/hosted-git-info.git"
},
"keywords": [
"git",
"github",
"bitbucket",
"gitlab"
],
"author": "GitHub Inc.",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/hosted-git-info/issues"
},
"homepage": "https://github.com/npm/hosted-git-info",
"scripts": {
"posttest": "npm run lint",
"snap": "tap",
"test": "tap",
"test:coverage": "tap --coverage-report=html",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
"template-oss-apply": "template-oss-apply --force"
},
"dependencies": {
"lru-cache": "^7.5.1"
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.7.1",
"tap": "^16.0.1"
},
"files": [
"bin/",
"lib/"
],
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"tap": {
"color": 1,
"coverage": true,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.7.1"
}
}

View File

@@ -0,0 +1,15 @@
The ISC License
Copyright (c) npm, Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,96 @@
# npm-package-arg
[![Build Status](https://travis-ci.org/npm/npm-package-arg.svg?branch=master)](https://travis-ci.org/npm/npm-package-arg)
Parses package name and specifier passed to commands like `npm install` or
`npm cache add`, or as found in `package.json` dependency sections.
## EXAMPLES
```javascript
var assert = require("assert")
var npa = require("npm-package-arg")
// Pass in the descriptor, and it'll return an object
try {
var parsed = npa("@bar/foo@1.2")
} catch (ex) {
}
```
## USING
`var npa = require('npm-package-arg')`
### var result = npa(*arg*[, *where*])
* *arg* - a string that you might pass to `npm install`, like:
`foo@1.2`, `@bar/foo@1.2`, `foo@user/foo`, `http://x.com/foo.tgz`,
`git+https://github.com/user/foo`, `bitbucket:user/foo`, `foo.tar.gz`,
`../foo/bar/` or `bar`. If the *arg* you provide doesn't have a specifier
part, eg `foo` then the specifier will default to `latest`.
* *where* - Optionally the path to resolve file paths relative to. Defaults to `process.cwd()`
**Throws** if the package name is invalid, a dist-tag is invalid or a URL's protocol is not supported.
### var result = npa.resolve(*name*, *spec*[, *where*])
* *name* - The name of the module you want to install. For example: `foo` or `@bar/foo`.
* *spec* - The specifier indicating where and how you can get this module. Something like:
`1.2`, `^1.7.17`, `http://x.com/foo.tgz`, `git+https://github.com/user/foo`,
`bitbucket:user/foo`, `file:foo.tar.gz` or `file:../foo/bar/`. If not
included then the default is `latest`.
* *where* - Optionally the path to resolve file paths relative to. Defaults to `process.cwd()`
**Throws** if the package name is invalid, a dist-tag is invalid or a URL's protocol is not supported.
### var purl = npa.toPurl(*arg*, *reg*)
Returns the [purl (package URL)](https://github.com/package-url/purl-spec) form of the given pacakge name/spec.
* *arg* - A package/version string. For example: `foo@1.0.0` or `@bar/foo@2.0.0-alpha.1`.
* *reg* - Optionally the URL to the package registry. If not specified, assumes the default
`https://registry.npmjs.org`.
**Throws** if the package name is invalid, or the supplied arg can't be resolved to a purl.
## RESULT OBJECT
The objects that are returned by npm-package-arg contain the following
keys:
* `type` - One of the following strings:
* `git` - A git repo
* `tag` - A tagged version, like `"foo@latest"`
* `version` - A specific version number, like `"foo@1.2.3"`
* `range` - A version range, like `"foo@2.x"`
* `file` - A local `.tar.gz`, `.tar` or `.tgz` file.
* `directory` - A local directory.
* `remote` - An http url (presumably to a tgz)
* `alias` - A specifier with an alias, like `myalias@npm:foo@1.2.3`
* `registry` - If true this specifier refers to a resource hosted on a
registry. This is true for `tag`, `version` and `range` types.
* `name` - If known, the `name` field expected in the resulting pkg.
* `scope` - If a name is something like `@org/module` then the `scope`
field will be set to `@org`. If it doesn't have a scoped name, then
scope is `null`.
* `escapedName` - A version of `name` escaped to match the npm scoped packages
specification. Mostly used when making requests against a registry. When
`name` is `null`, `escapedName` will also be `null`.
* `rawSpec` - The specifier part that was parsed out in calls to `npa(arg)`,
or the value of `spec` in calls to `npa.resolve(name, spec).
* `saveSpec` - The normalized specifier, for saving to package.json files.
`null` for registry dependencies.
* `fetchSpec` - The version of the specifier to be used to fetch this
resource. `null` for shortcuts to hosted git dependencies as there isn't
just one URL to try with them.
* `gitRange` - If set, this is a semver specifier to match against git tags with
* `gitCommittish` - If set, this is the specific committish to use with a git dependency.
* `hosted` - If `from === 'hosted'` then this will be a `hosted-git-info`
object. This property is not included when serializing the object as
JSON.
* `raw` - The original un-modified string that was provided. If called as
`npa.resolve(name, spec)` then this will be `name + '@' + spec`.
* `subSpec` - If `type === 'alias'`, this is a Result Object for parsing the
target specifier for the alias.

View File

@@ -0,0 +1,431 @@
'use strict'
module.exports = npa
module.exports.resolve = resolve
module.exports.toPurl = toPurl
module.exports.Result = Result
const url = require('url')
const HostedGit = require('hosted-git-info')
const semver = require('semver')
const path = global.FAKE_WINDOWS ? require('path').win32 : require('path')
const validatePackageName = require('validate-npm-package-name')
const { homedir } = require('os')
const log = require('proc-log')
const isWindows = process.platform === 'win32' || global.FAKE_WINDOWS
const hasSlashes = isWindows ? /\\|[/]/ : /[/]/
const isURL = /^(?:git[+])?[a-z]+:/i
const isGit = /^[^@]+@[^:.]+\.[^:]+:.+$/i
const isFilename = /[.](?:tgz|tar.gz|tar)$/i
function npa (arg, where) {
let name
let spec
if (typeof arg === 'object') {
if (arg instanceof Result && (!where || where === arg.where)) {
return arg
} else if (arg.name && arg.rawSpec) {
return npa.resolve(arg.name, arg.rawSpec, where || arg.where)
} else {
return npa(arg.raw, where || arg.where)
}
}
const nameEndsAt = arg[0] === '@' ? arg.slice(1).indexOf('@') + 1 : arg.indexOf('@')
const namePart = nameEndsAt > 0 ? arg.slice(0, nameEndsAt) : arg
if (isURL.test(arg)) {
spec = arg
} else if (isGit.test(arg)) {
spec = `git+ssh://${arg}`
} else if (namePart[0] !== '@' && (hasSlashes.test(namePart) || isFilename.test(namePart))) {
spec = arg
} else if (nameEndsAt > 0) {
name = namePart
spec = arg.slice(nameEndsAt + 1) || '*'
} else {
const valid = validatePackageName(arg)
if (valid.validForOldPackages) {
name = arg
spec = '*'
} else {
spec = arg
}
}
return resolve(name, spec, where, arg)
}
const isFilespec = isWindows ? /^(?:[.]|~[/]|[/\\]|[a-zA-Z]:)/ : /^(?:[.]|~[/]|[/]|[a-zA-Z]:)/
function resolve (name, spec, where, arg) {
const res = new Result({
raw: arg,
name: name,
rawSpec: spec,
fromArgument: arg != null,
})
if (name) {
res.setName(name)
}
if (spec && (isFilespec.test(spec) || /^file:/i.test(spec))) {
return fromFile(res, where)
} else if (spec && /^npm:/i.test(spec)) {
return fromAlias(res, where)
}
const hosted = HostedGit.fromUrl(spec, {
noGitPlus: true,
noCommittish: true,
})
if (hosted) {
return fromHostedGit(res, hosted)
} else if (spec && isURL.test(spec)) {
return fromURL(res)
} else if (spec && (hasSlashes.test(spec) || isFilename.test(spec))) {
return fromFile(res, where)
} else {
return fromRegistry(res)
}
}
const defaultRegistry = 'https://registry.npmjs.org'
function toPurl (arg, reg = defaultRegistry) {
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 !== defaultRegistry) {
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('; ')}.`)
err.code = 'EINVALIDPACKAGENAME'
return err
}
function invalidTagName (name, raw) {
// eslint-disable-next-line max-len
const err = new Error(`Invalid tag name "${name}" of package "${raw}": Tags may not have any characters that encodeURIComponent encodes.`)
err.code = 'EINVALIDTAGNAME'
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 for "version" types.`)
err.code = 'EINVALIDPURLTYPE'
return err
}
function Result (opts) {
this.type = opts.type
this.registry = opts.registry
this.where = opts.where
if (opts.raw == null) {
this.raw = opts.name ? opts.name + '@' + opts.rawSpec : opts.rawSpec
} else {
this.raw = opts.raw
}
this.name = undefined
this.escapedName = undefined
this.scope = undefined
this.rawSpec = opts.rawSpec || ''
this.saveSpec = opts.saveSpec
this.fetchSpec = opts.fetchSpec
if (opts.name) {
this.setName(opts.name)
}
this.gitRange = opts.gitRange
this.gitCommittish = opts.gitCommittish
this.gitSubdir = opts.gitSubdir
this.hosted = opts.hosted
}
Result.prototype.setName = function (name) {
const valid = validatePackageName(name)
if (!valid.validForOldPackages) {
throw invalidPackageName(name, valid, this.raw)
}
this.name = name
this.scope = name[0] === '@' ? name.slice(0, name.indexOf('/')) : undefined
// scoped packages in couch must have slash url-encoded, e.g. @foo%2Fbar
this.escapedName = name.replace('/', '%2f')
return this
}
Result.prototype.toString = function () {
const full = []
if (this.name != null && this.name !== '') {
full.push(this.name)
}
const spec = this.saveSpec || this.fetchSpec || this.rawSpec
if (spec != null && spec !== '') {
full.push(spec)
}
return full.length ? full.join('@') : this.raw
}
Result.prototype.toJSON = function () {
const result = Object.assign({}, this)
delete result.hosted
return result
}
function setGitCommittish (res, committish) {
if (!committish) {
res.gitCommittish = null
return res
}
// for each :: separated item:
for (const part of committish.split('::')) {
// if the item has no : the n it is a commit-ish
if (!part.includes(':')) {
if (res.gitRange) {
throw new Error('cannot override existing semver range with a committish')
}
if (res.gitCommittish) {
throw new Error('cannot override existing committish with a second committish')
}
res.gitCommittish = part
continue
}
// split on name:value
const [name, value] = part.split(':')
// if name is semver do semver lookup of ref or tag
if (name === 'semver') {
if (res.gitCommittish) {
throw new Error('cannot override existing committish with a semver range')
}
if (res.gitRange) {
throw new Error('cannot override existing semver range with a second semver range')
}
res.gitRange = decodeURIComponent(value)
continue
}
if (name === 'path') {
if (res.gitSubdir) {
throw new Error('cannot override existing path with a second path')
}
res.gitSubdir = `/${value}`
continue
}
log.warn('npm-package-arg', `ignoring unknown key "${name}"`)
}
return res
}
function fromFile (res, where) {
if (!where) {
where = process.cwd()
}
res.type = isFilename.test(res.rawSpec) ? 'file' : 'directory'
res.where = where
// always put the '/' on where when resolving urls, or else
// file:foo from /path/to/bar goes to /path/to/foo, when we want
// it to be /path/to/bar/foo
let specUrl
let resolvedUrl
const prefix = (!/^file:/.test(res.rawSpec) ? 'file:' : '')
const rawWithPrefix = prefix + res.rawSpec
let rawNoPrefix = rawWithPrefix.replace(/^file:/, '')
try {
resolvedUrl = new url.URL(rawWithPrefix, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawWithPrefix)
} catch (originalError) {
const er = new Error('Invalid file: URL, must comply with RFC 8909')
throw Object.assign(er, {
raw: res.rawSpec,
spec: res,
where,
originalError,
})
}
// environment switch for testing
if (process.env.NPM_PACKAGE_ARG_8909_STRICT !== '1') {
// XXX backwards compatibility lack of compliance with 8909
// Remove when we want a breaking change to come into RFC compliance.
if (resolvedUrl.host && resolvedUrl.host !== 'localhost') {
const rawSpec = res.rawSpec.replace(/^file:\/\//, 'file:///')
resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawSpec)
rawNoPrefix = rawSpec.replace(/^file:/, '')
}
// turn file:/../foo into file:../foo
// for 1, 2 or 3 leading slashes since we attempted
// in the previous step to make it a file protocol url with a leading slash
if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) {
const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:')
resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawSpec)
rawNoPrefix = rawSpec.replace(/^file:/, '')
}
// XXX end 8909 violation backwards compatibility section
}
// file:foo - relative url to ./foo
// file:/foo - absolute path /foo
// file:///foo - absolute path to /foo, no authority host
// file://localhost/foo - absolute path to /foo, on localhost
// file://foo - absolute path to / on foo host (error!)
if (resolvedUrl.host && resolvedUrl.host !== 'localhost') {
const msg = `Invalid file: URL, must be absolute if // present`
throw Object.assign(new Error(msg), {
raw: res.rawSpec,
parsed: resolvedUrl,
})
}
// turn /C:/blah into just C:/blah on windows
let specPath = decodeURIComponent(specUrl.pathname)
let resolvedPath = decodeURIComponent(resolvedUrl.pathname)
if (isWindows) {
specPath = specPath.replace(/^\/+([a-z]:\/)/i, '$1')
resolvedPath = resolvedPath.replace(/^\/+([a-z]:\/)/i, '$1')
}
// replace ~ with homedir, but keep the ~ in the saveSpec
// otherwise, make it relative to where param
if (/^\/~(\/|$)/.test(specPath)) {
res.saveSpec = `file:${specPath.substr(1)}`
resolvedPath = path.resolve(homedir(), specPath.substr(3))
} else if (!path.isAbsolute(rawNoPrefix)) {
res.saveSpec = `file:${path.relative(where, resolvedPath)}`
} else {
res.saveSpec = `file:${path.resolve(resolvedPath)}`
}
res.fetchSpec = path.resolve(where, resolvedPath)
return res
}
function fromHostedGit (res, hosted) {
res.type = 'git'
res.hosted = hosted
res.saveSpec = hosted.toString({ noGitPlus: false, noCommittish: false })
res.fetchSpec = hosted.getDefaultRepresentation() === 'shortcut' ? null : hosted.toString()
return setGitCommittish(res, hosted.committish)
}
function unsupportedURLType (protocol, spec) {
const err = new Error(`Unsupported URL Type "${protocol}": ${spec}`)
err.code = 'EUNSUPPORTEDPROTOCOL'
return err
}
function matchGitScp (spec) {
// git ssh specifiers are overloaded to also use scp-style git
// specifiers, so we have to parse those out and treat them special.
// They are NOT true URIs, so we can't hand them to `url.parse`.
//
// This regex looks for things that look like:
// git+ssh://git@my.custom.git.com:username/project.git#deadbeef
//
// ...and various combinations. The username in the beginning is *required*.
const matched = spec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i)
return matched && !matched[1].match(/:[0-9]+\/?.*$/i) && {
fetchSpec: matched[1],
gitCommittish: matched[2] == null ? null : matched[2],
}
}
function fromURL (res) {
// eslint-disable-next-line node/no-deprecated-api
const urlparse = url.parse(res.rawSpec)
res.saveSpec = res.rawSpec
// check the protocol, and then see if it's git or not
switch (urlparse.protocol) {
case 'git:':
case 'git+http:':
case 'git+https:':
case 'git+rsync:':
case 'git+ftp:':
case 'git+file:':
case 'git+ssh:': {
res.type = 'git'
const match = urlparse.protocol === 'git+ssh:' ? matchGitScp(res.rawSpec)
: null
if (match) {
setGitCommittish(res, match.gitCommittish)
res.fetchSpec = match.fetchSpec
} else {
setGitCommittish(res, urlparse.hash != null ? urlparse.hash.slice(1) : '')
urlparse.protocol = urlparse.protocol.replace(/^git[+]/, '')
if (urlparse.protocol === 'file:' && /^git\+file:\/\/[a-z]:/i.test(res.rawSpec)) {
// keep the drive letter : on windows file paths
urlparse.host += ':'
urlparse.hostname += ':'
}
delete urlparse.hash
res.fetchSpec = url.format(urlparse)
}
break
}
case 'http:':
case 'https:':
res.type = 'remote'
res.fetchSpec = res.saveSpec
break
default:
throw unsupportedURLType(urlparse.protocol, res.rawSpec)
}
return res
}
function fromAlias (res, where) {
const subSpec = npa(res.rawSpec.substr(4), where)
if (subSpec.type === 'alias') {
throw new Error('nested aliases not supported')
}
if (!subSpec.registry) {
throw new Error('aliases only work for registry deps')
}
res.subSpec = subSpec
res.registry = true
res.type = 'alias'
res.saveSpec = null
res.fetchSpec = null
return res
}
function fromRegistry (res) {
res.registry = true
const spec = res.rawSpec.trim()
// no save spec for registry components as we save based on the fetched
// version, not on the argument so this can't compute that.
res.saveSpec = null
res.fetchSpec = spec
const version = semver.valid(spec, true)
const range = semver.validRange(spec, true)
if (version) {
res.type = 'version'
} else if (range) {
res.type = 'range'
} else {
if (encodeURIComponent(spec) !== spec) {
throw invalidTagName(spec, res.raw)
}
res.type = 'tag'
}
return res
}

View File

@@ -0,0 +1,59 @@
{
"name": "npm-package-arg",
"version": "10.1.0",
"description": "Parse the things that can be arguments to `npm install`",
"main": "./lib/npa.js",
"directories": {
"test": "test"
},
"files": [
"bin/",
"lib/"
],
"dependencies": {
"hosted-git-info": "^6.0.0",
"proc-log": "^3.0.0",
"semver": "^7.3.5",
"validate-npm-package-name": "^5.0.0"
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.10.0",
"tap": "^16.0.1"
},
"scripts": {
"test": "tap",
"snap": "tap",
"npmclilint": "npmcli-lint",
"lint": "eslint \"**/*.js\"",
"lintfix": "npm run lint -- --fix",
"posttest": "npm run lint",
"postsnap": "npm run lintfix --",
"postlint": "template-oss-check",
"template-oss-apply": "template-oss-apply --force"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/npm-package-arg.git"
},
"author": "GitHub Inc.",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/npm-package-arg/issues"
},
"homepage": "https://github.com/npm/npm-package-arg",
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"tap": {
"branches": 97,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.10.0"
}
}

View File

@@ -0,0 +1,15 @@
The ISC License
Copyright (c) GitHub, Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,90 @@
# proc-log
Emits 'log' events on the process object which a log output listener can
consume and print to the terminal.
This is used by various modules within the npm CLI stack in order to send
log events that can be consumed by a listener on the process object.
## API
* `log.error(...args)` calls `process.emit('log', 'error', ...args)`
The highest log level. For printing extremely serious errors that
indicate something went wrong.
* `log.warn(...args)` calls `process.emit('log', 'warn', ...args)`
A fairly high log level. Things that the user needs to be aware of, but
which won't necessarily cause improper functioning of the system.
* `log.notice(...args)` calls `process.emit('log', 'notice', ...args)`
Notices which are important, but not necessarily dangerous or a cause for
excess concern.
* `log.info(...args)` calls `process.emit('log', 'info', ...args)`
Informative messages that may benefit the user, but aren't particularly
important.
* `log.verbose(...args)` calls `process.emit('log', 'verbose', ...args)`
Noisy output that is more detail that most users will care about.
* `log.silly(...args)` calls `process.emit('log', 'silly', ...args)`
Extremely noisy excessive logging messages that are typically only useful
for debugging.
* `log.http(...args)` calls `process.emit('log', 'http', ...args)`
Information about HTTP requests made and/or completed.
* `log.pause()` calls `process.emit('log', 'pause')` Used to tell
the consumer to stop printing messages.
* `log.resume()` calls `process.emit('log', 'resume')`
Used to tell the consumer that it is ok to print messages again.
* `log.LEVELS` an array of strings of all log method names
## Examples
Every method calls `process.emit('log', level, ...otherArgs)` internally.
So in order to consume those events you need to do `process.on('log', fn)`.
### Colorize based on level
Here's an example of how to consume `proc-log` events and colorize them
based on level:
```js
const chalk = require('chalk')
process.on('log', (level, ...args) => {
if (level === 'error') {
console.log(chalk.red(level), ...args)
} else {
console.log(chalk.blue(level), ...args)
}
})
```
### Pause and resume
`pause` and `resume` are included so you have the ability to tell your consumer
that you want to pause or resume your display of logs. In the npm CLI we use
this to buffer all logs on init until we know the correct loglevel to display.
But we also setup a second handler that writes everything to a file even if
paused.
```js
let paused = true
const buffer = []
// this handler will buffer and replay logs only
// after `procLog.resume()` is called
process.on('log', (level, ...args) => {
if (level === 'resume') {
buffer.forEach((item) => console.log(...item))
paused = false
return
} 
if (paused) {
buffer.push([level, ...args])
} else {
console.log(level, ...args)
}
})
// this handler will write everything to a file
process.on('log', (...args) => {
fs.appendFileSync('debug.log', args.join(' '))
})
```

View File

@@ -0,0 +1,23 @@
// emits 'log' events on the process
const LEVELS = [
'notice',
'error',
'warn',
'info',
'verbose',
'http',
'silly',
'pause',
'resume',
]
const log = level => (...args) => process.emit('log', level, ...args)
const logger = {}
for (const level of LEVELS) {
logger[level] = log(level)
}
logger.LEVELS = LEVELS
module.exports = logger

View File

@@ -0,0 +1,44 @@
{
"name": "proc-log",
"version": "3.0.0",
"files": [
"bin/",
"lib/"
],
"main": "lib/index.js",
"description": "just emit 'log' events on the process object",
"repository": {
"type": "git",
"url": "https://github.com/npm/proc-log.git"
},
"author": "GitHub Inc.",
"license": "ISC",
"scripts": {
"test": "tap",
"snap": "tap",
"posttest": "npm run lint",
"postsnap": "eslint index.js test/*.js --fix",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
"template-oss-apply": "template-oss-apply --force"
},
"devDependencies": {
"@npmcli/eslint-config": "^3.0.1",
"@npmcli/template-oss": "4.5.1",
"tap": "^16.0.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.5.1"
},
"tap": {
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
}
}

View File

@@ -0,0 +1,6 @@
Copyright (c) 2015, npm, Inc
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,120 @@
# validate-npm-package-name
Give me a string and I'll tell you if it's a valid `npm` package name.
This package exports a single synchronous function that takes a `string` as
input and returns an object with two properties:
- `validForNewPackages` :: `Boolean`
- `validForOldPackages` :: `Boolean`
## Contents
- [Naming rules](#naming-rules)
- [Examples](#examples)
+ [Valid Names](#valid-names)
+ [Invalid Names](#invalid-names)
- [Legacy Names](#legacy-names)
- [Tests](#tests)
- [License](#license)
## Naming Rules
Below is a list of rules that valid `npm` package name should conform to.
- package name length should be greater than zero
- all the characters in the package name must be lowercase i.e., no uppercase or mixed case names are allowed
- package name *can* consist of hyphens
- package name must *not* contain any non-url-safe characters (since name ends up being part of a URL)
- package name should not start with `.` or `_`
- package name should *not* contain any spaces
- package name should *not* contain any of the following characters: `~)('!*`
- package name *cannot* be the same as a node.js/io.js core module nor a reserved/blacklisted name. For example, the following names are invalid:
+ http
+ stream
+ node_modules
+ favicon.ico
- package name length cannot exceed 214
## Examples
### Valid Names
```js
var validate = require("validate-npm-package-name")
validate("some-package")
validate("example.com")
validate("under_score")
validate("123numeric")
validate("@npm/thingy")
validate("@jane/foo.js")
```
All of the above names are valid, so you'll get this object back:
```js
{
validForNewPackages: true,
validForOldPackages: true
}
```
### Invalid Names
```js
validate("excited!")
validate(" leading-space:and:weirdchars")
```
That was never a valid package name, so you get this:
```js
{
validForNewPackages: false,
validForOldPackages: false,
errors: [
'name cannot contain leading or trailing spaces',
'name can only contain URL-friendly characters'
]
}
```
## Legacy Names
In the old days of npm, package names were wild. They could have capital
letters in them. They could be really long. They could be the name of an
existing module in node core.
If you give this function a package name that **used to be valid**, you'll see
a change in the value of `validForNewPackages` property, and a warnings array
will be present:
```js
validate("eLaBorAtE-paCkAgE-with-mixed-case-and-more-than-214-characters-----------------------------------------------------------------------------------------------------------------------------------------------------------")
```
returns:
```js
{
validForNewPackages: false,
validForOldPackages: true,
warnings: [
"name can no longer contain capital letters",
"name can no longer contain more than 214 characters"
]
}
```
## Tests
```sh
npm install
npm test
```
## License
ISC

View File

@@ -0,0 +1,107 @@
'use strict'
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
var builtins = require('builtins')
var blacklist = [
'node_modules',
'favicon.ico',
]
function validate (name) {
var warnings = []
var errors = []
if (name === null) {
errors.push('name cannot be null')
return done(warnings, errors)
}
if (name === undefined) {
errors.push('name cannot be undefined')
return done(warnings, errors)
}
if (typeof name !== 'string') {
errors.push('name must be a string')
return done(warnings, errors)
}
if (!name.length) {
errors.push('name length must be greater than zero')
}
if (name.match(/^\./)) {
errors.push('name cannot start with a period')
}
if (name.match(/^_/)) {
errors.push('name cannot start with an underscore')
}
if (name.trim() !== name) {
errors.push('name cannot contain leading or trailing spaces')
}
// No funny business
blacklist.forEach(function (blacklistedName) {
if (name.toLowerCase() === blacklistedName) {
errors.push(blacklistedName + ' is a blacklisted name')
}
})
// Generate warnings for stuff that used to be allowed
// core module names like http, events, util, etc
builtins({ version: '*' }).forEach(function (builtin) {
if (name.toLowerCase() === builtin) {
warnings.push(builtin + ' is a core module name')
}
})
if (name.length > 214) {
warnings.push('name can no longer contain more than 214 characters')
}
// mIxeD CaSe nAMEs
if (name.toLowerCase() !== name) {
warnings.push('name can no longer contain capital letters')
}
if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) {
warnings.push('name can no longer contain special characters ("~\'!()*")')
}
if (encodeURIComponent(name) !== name) {
// Maybe it's a scoped package name, like @user/package
var nameMatch = name.match(scopedPackagePattern)
if (nameMatch) {
var user = nameMatch[1]
var pkg = nameMatch[2]
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
return done(warnings, errors)
}
}
errors.push('name can only contain URL-friendly characters')
}
return done(warnings, errors)
}
var done = function (warnings, errors) {
var result = {
validForNewPackages: errors.length === 0 && warnings.length === 0,
validForOldPackages: errors.length === 0,
warnings: warnings,
errors: errors,
}
if (!result.warnings.length) {
delete result.warnings
}
if (!result.errors.length) {
delete result.errors
}
return result
}
module.exports = validate

View File

@@ -0,0 +1,65 @@
{
"name": "validate-npm-package-name",
"version": "5.0.0",
"description": "Give me a string and I'll tell you if it's a valid npm package name",
"main": "lib/",
"directories": {
"test": "test"
},
"dependencies": {
"builtins": "^5.0.0"
},
"devDependencies": {
"@npmcli/eslint-config": "^3.0.1",
"@npmcli/template-oss": "4.5.1",
"tap": "^16.0.1"
},
"scripts": {
"cov:test": "TAP_FLAGS='--cov' npm run test:code",
"test:code": "tap ${TAP_FLAGS:-'--'} test/*.js",
"test:style": "standard",
"test": "tap",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"template-oss-apply": "template-oss-apply --force",
"lintfix": "npm run lint -- --fix",
"snap": "tap",
"posttest": "npm run lint"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/validate-npm-package-name.git"
},
"keywords": [
"npm",
"package",
"names",
"validation"
],
"author": "GitHub Inc.",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/validate-npm-package-name/issues"
},
"homepage": "https://github.com/npm/validate-npm-package-name",
"files": [
"bin/",
"lib/"
],
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.5.1"
},
"tap": {
"statements": 88,
"branches": 92,
"lines": 88,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
}
}

56
front/app/node_modules/npm-pick-manifest/package.json generated vendored Normal file
View File

@@ -0,0 +1,56 @@
{
"name": "npm-pick-manifest",
"version": "8.0.1",
"description": "Resolves a matching manifest from a package metadata document according to standard npm semver resolution rules.",
"main": "./lib",
"files": [
"bin/",
"lib/"
],
"scripts": {
"coverage": "tap",
"lint": "eslint \"**/*.js\"",
"test": "tap",
"posttest": "npm run lint",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
"snap": "tap",
"template-oss-apply": "template-oss-apply --force"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/npm-pick-manifest.git"
},
"keywords": [
"npm",
"semver",
"package manager"
],
"author": "GitHub Inc.",
"license": "ISC",
"dependencies": {
"npm-install-checks": "^6.0.0",
"npm-normalize-package-bin": "^3.0.0",
"npm-package-arg": "^10.0.0",
"semver": "^7.3.5"
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.6.1",
"tap": "^16.0.1"
},
"tap": {
"check-coverage": true,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.6.1"
}
}