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

15
front/app/node_modules/pacote/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter, Kat Marchán, npm, Inc., and Contributors
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.

281
front/app/node_modules/pacote/README.md generated vendored Normal file
View File

@@ -0,0 +1,281 @@
# pacote
Fetches package manifests and tarballs from the npm registry.
## USAGE
```js
const pacote = require('pacote')
// get a package manifest
pacote.manifest('foo@1.x').then(manifest => console.log('got it', manifest))
// extract a package into a folder
pacote.extract('github:npm/cli', 'some/path', options)
.then(({from, resolved, integrity}) => {
console.log('extracted!', from, resolved, integrity)
})
pacote.tarball('https://server.com/package.tgz').then(data => {
console.log('got ' + data.length + ' bytes of tarball data')
})
```
`pacote` works with any kind of package specifier that npm can install. If
you can pass it to the npm CLI, you can pass it to pacote. (In fact, that's
exactly what the npm CLI does.)
Anything that you can do with one kind of package, you can do with another.
Data that isn't relevant (like a packument for a tarball) will be
simulated.
`prepare` scripts will be run when generating tarballs from `git` and
`directory` locations, to simulate what _would_ be published to the
registry, so that you get a working package instead of just raw source
code that might need to be transpiled.
## CLI
This module exports a command line interface that can do most of what is
described below. Run `pacote -h` to learn more.
```
Pacote - The JavaScript Package Handler, v10.1.1
Usage:
pacote resolve <spec>
Resolve a specifier and output the fully resolved target
Returns integrity and from if '--long' flag is set.
pacote manifest <spec>
Fetch a manifest and print to stdout
pacote packument <spec>
Fetch a full packument and print to stdout
pacote tarball <spec> [<filename>]
Fetch a package tarball and save to <filename>
If <filename> is missing or '-', the tarball will be streamed to stdout.
pacote extract <spec> <folder>
Extract a package to the destination folder.
Configuration values all match the names of configs passed to npm, or
options passed to Pacote. Additional flags for this executable:
--long Print an object from 'resolve', including integrity and spec.
--json Print result objects as JSON rather than node's default.
(This is the default if stdout is not a TTY.)
--help -h Print this helpful text.
For example '--cache=/path/to/folder' will use that folder as the cache.
```
## API
The `spec` refers to any kind of package specifier that npm can install.
If you can pass it to the npm CLI, you can pass it to pacote. (In fact,
that's exactly what the npm CLI does.)
See below for valid `opts` values.
* `pacote.resolve(spec, opts)` Resolve a specifier like `foo@latest` or
`github:user/project` all the way to a tarball url, tarball file, or git
repo with commit hash.
* `pacote.extract(spec, dest, opts)` Extract a package's tarball into a
destination folder. Returns a promise that resolves to the
`{from,resolved,integrity}` of the extracted package.
* `pacote.manifest(spec, opts)` Fetch (or simulate) a package's manifest
(basically, the `package.json` file, plus a bit of metadata).
See below for more on manifests and packuments. Returns a Promise that
resolves to the manifest object.
* `pacote.packument(spec, opts)` Fetch (or simulate) a package's packument
(basically, the top-level package document listing all the manifests that
the registry returns). See below for more on manifests and packuments.
Returns a Promise that resolves to the packument object.
* `pacote.tarball(spec, opts)` Get a package tarball data as a buffer in
memory. Returns a Promise that resolves to the tarball data Buffer, with
`from`, `resolved`, and `integrity` fields attached.
* `pacote.tarball.file(spec, dest, opts)` Save a package tarball data to
a file on disk. Returns a Promise that resolves to
`{from,integrity,resolved}` of the fetched tarball.
* `pacote.tarball.stream(spec, streamHandler, opts)` Fetch a tarball and
make the stream available to the `streamHandler` function.
This is mostly an internal function, but it is exposed because it does
provide some functionality that may be difficult to achieve otherwise.
The `streamHandler` function MUST return a Promise that resolves when
the stream (and all associated work) is ended, or rejects if the stream
has an error.
The `streamHandler` function MAY be called multiple times, as Pacote
retries requests in some scenarios, such as cache corruption or
retriable network failures.
### Options
Options are passed to
[`npm-registry-fetch`](http://npm.im/npm-registry-fetch) and
[`cacache`](http://npm.im/cacache), so in addition to these, anything for
those modules can be given to pacote as well.
Options object is cloned, and mutated along the way to add integrity,
resolved, and other properties, as they are determined.
* `cache` Where to store cache entries and temp files. Passed to
[`cacache`](http://npm.im/cacache). Defaults to the same cache directory
that npm will use by default, based on platform and environment.
* `where` Base folder for resolving relative `file:` dependencies.
* `resolved` Shortcut for looking up resolved values. Should be specified
if known.
* `integrity` Expected integrity of fetched package tarball. If specified,
tarballs with mismatched integrity values will raise an `EINTEGRITY`
error.
* `umask` Permission mode mask for extracted files and directories.
Defaults to `0o22`. See "Extracted File Modes" below.
* `fmode` Minimum permission mode for extracted files. Defaults to
`0o666`. See "Extracted File Modes" below.
* `dmode` Minimum permission mode for extracted directories. Defaults to
`0o777`. See "Extracted File Modes" below.
* `preferOnline` Prefer to revalidate cache entries, even when it would not
be strictly necessary. Default `false`.
* `before` When picking a manifest from a packument, only consider
packages published before the specified date. Default `null`.
* `defaultTag` The default `dist-tag` to use when choosing a manifest from a
packument. Defaults to `latest`.
* `registry` The npm registry to use by default. Defaults to
`https://registry.npmjs.org/`.
* `fullMetadata` Fetch the full metadata from the registry for packuments,
including information not strictly required for installation (author,
description, etc.) Defaults to `true` when `before` is set, since the
version publish time is part of the extended packument metadata.
* `fullReadJson` Use the slower `read-package-json` package insted of
`read-package-json-fast` in order to include extra fields like "readme" in
the manifest. Defaults to `false`.
* `packumentCache` For registry packuments only, you may provide a `Map`
object which will be used to cache packument requests between pacote
calls. This allows you to easily avoid hitting the registry multiple
times (even just to validate the cache) for a given packument, since it
is unlikely to change in the span of a single command.
* `silent` A boolean that determines whether the banner is displayed
when calling `@npmcli/run-script`.
* `verifySignatures` A boolean that will make pacote verify the
integrity signature of a manifest, if present. There must be a
configured `_keys` entry in the config that is scoped to the
registry the manifest is being fetched from.
### Advanced API
Each different type of fetcher is exposed for more advanced usage such as
using helper methods from this classes:
* `DirFetcher`
* `FileFetcher`
* `GitFetcher`
* `RegistryFetcher`
* `RemoteFetcher`
## Extracted File Modes
Files are extracted with a mode matching the following formula:
```
( (tarball entry mode value) | (minimum mode option) ) ~ (umask)
```
This is in order to prevent unreadable files or unlistable directories from
cluttering a project's `node_modules` folder, even if the package tarball
specifies that the file should be inaccessible.
It also prevents files from being group- or world-writable without explicit
opt-in by the user, because all file and directory modes are masked against
the `umask` value.
So, a file which is `0o771` in the tarball, using the default `fmode` of
`0o666` and `umask` of `0o22`, will result in a file mode of `0o755`:
```
(0o771 | 0o666) => 0o777
(0o777 ~ 0o22) => 0o755
```
In almost every case, the defaults are appropriate. To respect exactly
what is in the package tarball (even if this makes an unusable system), set
both `dmode` and `fmode` options to `0`. Otherwise, the `umask` config
should be used in most cases where file mode modifications are required,
and this functions more or less the same as the `umask` value in most Unix
systems.
## Extracted File Ownership
When running as `root` on Unix systems, all extracted files and folders
will have their owning `uid` and `gid` values set to match the ownership
of the containing folder.
This prevents `root`-owned files showing up in a project's `node_modules`
folder when a user runs `sudo npm install`.
## Manifests
A `manifest` is similar to a `package.json` file. However, it has a few
pieces of extra metadata, and sometimes lacks metadata that is inessential
to package installation.
In addition to the common `package.json` fields, manifests include:
* `manifest._resolved` The tarball url or file path where the package
artifact can be found.
* `manifest._from` A normalized form of the spec passed in as an argument.
* `manifest._integrity` The integrity value for the package artifact.
* `manifest._id` The canonical spec of this package version: name@version.
* `manifest.dist` Registry manifests (those included in a packument) have a
`dist` object. Only `tarball` is required, though at least one of
`shasum` or `integrity` is almost always present.
* `tarball` The url to the associated package artifact. (Copied by
Pacote to `manifest._resolved`.)
* `integrity` The integrity SRI string for the artifact. This may not
be present for older packages on the npm registry. (Copied by Pacote
to `manifest._integrity`.)
* `shasum` Legacy integrity value. Hexadecimal-encoded sha1 hash.
(Converted to an SRI string and copied by Pacote to
`manifest._integrity` when `dist.integrity` is not present.)
* `fileCount` Number of files in the tarball.
* `unpackedSize` Size on disk of the package when unpacked.
* `npm-signature` A signature of the package by the
[`npmregistry`](https://keybase.io/npmregistry) Keybase account.
(Obviously only present for packages published to
`https://registry.npmjs.org`.)
## Packuments
A packument is the top-level package document that lists the set of
manifests for available versions for a package.
When a packument is fetched with `accept:
application/vnd.npm.install-v1+json` in the HTTP headers, only the most
minimum necessary metadata is returned. Additional metadata is returned
when fetched with only `accept: application/json`.
For Pacote's purposes, the following fields are relevant:
* `versions` An object where each key is a version, and each value is the
manifest for that version.
* `dist-tags` An object mapping dist-tags to version numbers. This is how
`foo@latest` gets turned into `foo@1.2.3`.
* `time` In the full packument, an object mapping version numbers to
publication times, for the `opts.before` functionality.
Pacote adds the following field, regardless of the accept header:
* `_contentLength` The size of the packument.

158
front/app/node_modules/pacote/lib/bin.js generated vendored Executable file
View File

@@ -0,0 +1,158 @@
#!/usr/bin/env node
const run = conf => {
const pacote = require('../')
switch (conf._[0]) {
case 'resolve':
case 'manifest':
case 'packument':
if (conf._[0] === 'resolve' && conf.long) {
return pacote.manifest(conf._[1], conf).then(mani => ({
resolved: mani._resolved,
integrity: mani._integrity,
from: mani._from,
}))
}
return pacote[conf._[0]](conf._[1], conf)
case 'tarball':
if (!conf._[2] || conf._[2] === '-') {
return pacote.tarball.stream(conf._[1], stream => {
stream.pipe(
conf.testStdout ||
/* istanbul ignore next */
process.stdout
)
// make sure it resolves something falsey
return stream.promise().then(() => {
return false
})
}, conf)
} else {
return pacote.tarball.file(conf._[1], conf._[2], conf)
}
case 'extract':
return pacote.extract(conf._[1], conf._[2], conf)
default: /* istanbul ignore next */ {
throw new Error(`bad command: ${conf._[0]}`)
}
}
}
const version = require('../package.json').version
const usage = () =>
`Pacote - The JavaScript Package Handler, v${version}
Usage:
pacote resolve <spec>
Resolve a specifier and output the fully resolved target
Returns integrity and from if '--long' flag is set.
pacote manifest <spec>
Fetch a manifest and print to stdout
pacote packument <spec>
Fetch a full packument and print to stdout
pacote tarball <spec> [<filename>]
Fetch a package tarball and save to <filename>
If <filename> is missing or '-', the tarball will be streamed to stdout.
pacote extract <spec> <folder>
Extract a package to the destination folder.
Configuration values all match the names of configs passed to npm, or
options passed to Pacote. Additional flags for this executable:
--long Print an object from 'resolve', including integrity and spec.
--json Print result objects as JSON rather than node's default.
(This is the default if stdout is not a TTY.)
--help -h Print this helpful text.
For example '--cache=/path/to/folder' will use that folder as the cache.
`
const shouldJSON = (conf, result) =>
conf.json ||
!process.stdout.isTTY &&
conf.json === undefined &&
result &&
typeof result === 'object'
const pretty = (conf, result) =>
shouldJSON(conf, result) ? JSON.stringify(result, 0, 2) : result
let addedLogListener = false
const main = args => {
const conf = parse(args)
if (conf.help || conf.h) {
return console.log(usage())
}
if (!addedLogListener) {
process.on('log', console.error)
addedLogListener = true
}
try {
return run(conf)
.then(result => result && console.log(pretty(conf, result)))
.catch(er => {
console.error(er)
process.exit(1)
})
} catch (er) {
console.error(er.message)
console.error(usage())
}
}
const parseArg = arg => {
const split = arg.slice(2).split('=')
const k = split.shift()
const v = split.join('=')
const no = /^no-/.test(k) && !v
const key = (no ? k.slice(3) : k)
.replace(/^tag$/, 'defaultTag')
.replace(/-([a-z])/g, (_, c) => c.toUpperCase())
const value = v ? v.replace(/^~/, process.env.HOME) : !no
return { key, value }
}
const parse = args => {
const conf = {
_: [],
cache: process.env.HOME + '/.npm/_cacache',
}
let dashdash = false
args.forEach(arg => {
if (dashdash) {
conf._.push(arg)
} else if (arg === '--') {
dashdash = true
} else if (arg === '-h') {
conf.help = true
} else if (/^--/.test(arg)) {
const { key, value } = parseArg(arg)
conf[key] = value
} else {
conf._.push(arg)
}
})
return conf
}
if (module === require.main) {
main(process.argv.slice(2))
} else {
module.exports = {
main,
run,
usage,
parseArg,
parse,
}
}

108
front/app/node_modules/pacote/lib/dir.js generated vendored Normal file
View File

@@ -0,0 +1,108 @@
const Fetcher = require('./fetcher.js')
const FileFetcher = require('./file.js')
const Minipass = require('minipass')
const tarCreateOptions = require('./util/tar-create-options.js')
const packlist = require('npm-packlist')
const tar = require('tar')
const _prepareDir = Symbol('_prepareDir')
const { resolve } = require('path')
const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson')
const runScript = require('@npmcli/run-script')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
class DirFetcher extends Fetcher {
constructor (spec, opts) {
super(spec, opts)
// just the fully resolved filename
this.resolved = this.spec.fetchSpec
this.tree = opts.tree || null
this.Arborist = opts.Arborist || null
}
// exposes tarCreateOptions as public API
static tarCreateOptions (manifest) {
return tarCreateOptions(manifest)
}
get types () {
return ['directory']
}
[_prepareDir] () {
return this.manifest().then(mani => {
if (!mani.scripts || !mani.scripts.prepare) {
return
}
// we *only* run prepare.
// pre/post-pack is run by the npm CLI for publish and pack,
// but this function is *also* run when installing git deps
const stdio = this.opts.foregroundScripts ? 'inherit' : 'pipe'
// hide the banner if silent opt is passed in, or if prepare running
// in the background.
const banner = this.opts.silent ? false : stdio === 'inherit'
return runScript({
pkg: mani,
event: 'prepare',
path: this.resolved,
stdio,
banner,
env: {
npm_package_resolved: this.resolved,
npm_package_integrity: this.integrity,
npm_package_json: resolve(this.resolved, 'package.json'),
},
})
})
}
[_tarballFromResolved] () {
if (!this.tree && !this.Arborist) {
throw new Error('DirFetcher requires either a tree or an Arborist constructor to pack')
}
const stream = new Minipass()
stream.resolved = this.resolved
stream.integrity = this.integrity
const { prefix, workspaces } = this.opts
// run the prepare script, get the list of files, and tar it up
// pipe to the stream, and proxy errors the chain.
this[_prepareDir]()
.then(async () => {
if (!this.tree) {
const arb = new this.Arborist({ path: this.resolved })
this.tree = await arb.loadActual()
}
return packlist(this.tree, { path: this.resolved, prefix, workspaces })
})
.then(files => tar.c(tarCreateOptions(this.package), files)
.on('error', er => stream.emit('error', er)).pipe(stream))
.catch(er => stream.emit('error', er))
return stream
}
manifest () {
if (this.package) {
return Promise.resolve(this.package)
}
return this[_readPackageJson](this.resolved + '/package.json')
.then(mani => this.package = {
...mani,
_integrity: this.integrity && String(this.integrity),
_resolved: this.resolved,
_from: this.from,
})
}
packument () {
return FileFetcher.prototype.packument.apply(this)
}
}
module.exports = DirFetcher

504
front/app/node_modules/pacote/lib/fetcher.js generated vendored Normal file
View File

@@ -0,0 +1,504 @@
// This is the base class that the other fetcher types in lib
// all descend from.
// It handles the unpacking and retry logic that is shared among
// all of the other Fetcher types.
const npa = require('npm-package-arg')
const ssri = require('ssri')
const { promisify } = require('util')
const { basename, dirname } = require('path')
const tar = require('tar')
const log = require('proc-log')
const retry = require('promise-retry')
const fs = require('fs/promises')
const fsm = require('fs-minipass')
const cacache = require('cacache')
const isPackageBin = require('./util/is-package-bin.js')
const removeTrailingSlashes = require('./util/trailing-slashes.js')
const getContents = require('@npmcli/installed-package-contents')
const readPackageJsonFast = require('read-package-json-fast')
const readPackageJson = promisify(require('read-package-json'))
const Minipass = require('minipass')
const cacheDir = require('./util/cache-dir.js')
// Private methods.
// Child classes should not have to override these.
// Users should never call them.
const _extract = Symbol('_extract')
const _mkdir = Symbol('_mkdir')
const _empty = Symbol('_empty')
const _toFile = Symbol('_toFile')
const _tarxOptions = Symbol('_tarxOptions')
const _entryMode = Symbol('_entryMode')
const _istream = Symbol('_istream')
const _assertType = Symbol('_assertType')
const _tarballFromCache = Symbol('_tarballFromCache')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches')
const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson')
class FetcherBase {
constructor (spec, opts) {
if (!opts || typeof opts !== 'object') {
throw new TypeError('options object is required')
}
this.spec = npa(spec, opts.where)
this.allowGitIgnore = !!opts.allowGitIgnore
// a bit redundant because presumably the caller already knows this,
// but it makes it easier to not have to keep track of the requested
// spec when we're dispatching thousands of these at once, and normalizing
// is nice. saveSpec is preferred if set, because it turns stuff like
// x/y#committish into github:x/y#committish. use name@rawSpec for
// registry deps so that we turn xyz and xyz@ -> xyz@
this.from = this.spec.registry
? `${this.spec.name}@${this.spec.rawSpec}` : this.spec.saveSpec
this[_assertType]()
// clone the opts object so that others aren't upset when we mutate it
// by adding/modifying the integrity value.
this.opts = { ...opts }
this.cache = opts.cache || cacheDir()
this.resolved = opts.resolved || null
// default to caching/verifying with sha512, that's what we usually have
// need to change this default, or start overriding it, when sha512
// is no longer strong enough.
this.defaultIntegrityAlgorithm = opts.defaultIntegrityAlgorithm || 'sha512'
if (typeof opts.integrity === 'string') {
this.opts.integrity = ssri.parse(opts.integrity)
}
this.package = null
this.type = this.constructor.name
this.fmode = opts.fmode || 0o666
this.dmode = opts.dmode || 0o777
// we don't need a default umask, because we don't chmod files coming
// out of package tarballs. they're forced to have a mode that is
// valid, regardless of what's in the tarball entry, and then we let
// the process's umask setting do its job. but if configured, we do
// respect it.
this.umask = opts.umask || 0
this.preferOnline = !!opts.preferOnline
this.preferOffline = !!opts.preferOffline
this.offline = !!opts.offline
this.before = opts.before
this.fullMetadata = this.before ? true : !!opts.fullMetadata
this.fullReadJson = !!opts.fullReadJson
if (this.fullReadJson) {
this[_readPackageJson] = readPackageJson
} else {
this[_readPackageJson] = readPackageJsonFast
}
// rrh is a registry hostname or 'never' or 'always'
// defaults to registry.npmjs.org
this.replaceRegistryHost = (!opts.replaceRegistryHost || opts.replaceRegistryHost === 'npmjs') ?
'registry.npmjs.org' : opts.replaceRegistryHost
this.defaultTag = opts.defaultTag || 'latest'
this.registry = removeTrailingSlashes(opts.registry || 'https://registry.npmjs.org')
// command to run 'prepare' scripts on directories and git dirs
// To use pacote with yarn, for example, set npmBin to 'yarn'
// and npmCliConfig with yarn's equivalents.
this.npmBin = opts.npmBin || 'npm'
// command to install deps for preparing
this.npmInstallCmd = opts.npmInstallCmd || ['install', '--force']
// XXX fill more of this in based on what we know from this.opts
// we explicitly DO NOT fill in --tag, though, since we are often
// going to be packing in the context of a publish, which may set
// a dist-tag, but certainly wants to keep defaulting to latest.
this.npmCliConfig = opts.npmCliConfig || [
`--cache=${dirname(this.cache)}`,
`--prefer-offline=${!!this.preferOffline}`,
`--prefer-online=${!!this.preferOnline}`,
`--offline=${!!this.offline}`,
...(this.before ? [`--before=${this.before.toISOString()}`] : []),
'--no-progress',
'--no-save',
'--no-audit',
// override any omit settings from the environment
'--include=dev',
'--include=peer',
'--include=optional',
// we need the actual things, not just the lockfile
'--no-package-lock-only',
'--no-dry-run',
]
}
get integrity () {
return this.opts.integrity || null
}
set integrity (i) {
if (!i) {
return
}
i = ssri.parse(i)
const current = this.opts.integrity
// do not ever update an existing hash value, but do
// merge in NEW algos and hashes that we don't already have.
if (current) {
current.merge(i)
} else {
this.opts.integrity = i
}
}
get notImplementedError () {
return new Error('not implemented in this fetcher type: ' + this.type)
}
// override in child classes
// Returns a Promise that resolves to this.resolved string value
resolve () {
return this.resolved ? Promise.resolve(this.resolved)
: Promise.reject(this.notImplementedError)
}
packument () {
return Promise.reject(this.notImplementedError)
}
// override in child class
// returns a manifest containing:
// - name
// - version
// - _resolved
// - _integrity
// - plus whatever else was in there (corgi, full metadata, or pj file)
manifest () {
return Promise.reject(this.notImplementedError)
}
// private, should be overridden.
// Note that they should *not* calculate or check integrity or cache,
// but *just* return the raw tarball data stream.
[_tarballFromResolved] () {
throw this.notImplementedError
}
// public, should not be overridden
tarball () {
return this.tarballStream(stream => stream.concat().then(data => {
data.integrity = this.integrity && String(this.integrity)
data.resolved = this.resolved
data.from = this.from
return data
}))
}
// private
// Note: cacache will raise a EINTEGRITY error if the integrity doesn't match
[_tarballFromCache] () {
return cacache.get.stream.byDigest(this.cache, this.integrity, this.opts)
}
get [_cacheFetches] () {
return true
}
[_istream] (stream) {
// if not caching this, just return it
if (!this.opts.cache || !this[_cacheFetches]) {
// instead of creating a new integrity stream, we only piggyback on the
// provided stream's events
if (stream.hasIntegrityEmitter) {
stream.on('integrity', i => this.integrity = i)
return stream
}
const istream = ssri.integrityStream(this.opts)
istream.on('integrity', i => this.integrity = i)
stream.on('error', err => istream.emit('error', err))
return stream.pipe(istream)
}
// we have to return a stream that gets ALL the data, and proxies errors,
// but then pipe from the original tarball stream into the cache as well.
// To do this without losing any data, and since the cacache put stream
// is not a passthrough, we have to pipe from the original stream into
// the cache AFTER we pipe into the middleStream. Since the cache stream
// has an asynchronous flush to write its contents to disk, we need to
// defer the middleStream end until the cache stream ends.
const middleStream = new Minipass()
stream.on('error', err => middleStream.emit('error', err))
stream.pipe(middleStream, { end: false })
const cstream = cacache.put.stream(
this.opts.cache,
`pacote:tarball:${this.from}`,
this.opts
)
cstream.on('integrity', i => this.integrity = i)
cstream.on('error', err => stream.emit('error', err))
stream.pipe(cstream)
// eslint-disable-next-line promise/catch-or-return
cstream.promise().catch(() => {}).then(() => middleStream.end())
return middleStream
}
pickIntegrityAlgorithm () {
return this.integrity ? this.integrity.pickAlgorithm(this.opts)
: this.defaultIntegrityAlgorithm
}
// TODO: check error class, once those are rolled out to our deps
isDataCorruptionError (er) {
return er.code === 'EINTEGRITY' || er.code === 'Z_DATA_ERROR'
}
// override the types getter
get types () {
return false
}
[_assertType] () {
if (this.types && !this.types.includes(this.spec.type)) {
throw new TypeError(`Wrong spec type (${
this.spec.type
}) for ${
this.constructor.name
}. Supported types: ${this.types.join(', ')}`)
}
}
// We allow ENOENTs from cacache, but not anywhere else.
// An ENOENT trying to read a tgz file, for example, is Right Out.
isRetriableError (er) {
// TODO: check error class, once those are rolled out to our deps
return this.isDataCorruptionError(er) ||
er.code === 'ENOENT' ||
er.code === 'EISDIR'
}
// Mostly internal, but has some uses
// Pass in a function which returns a promise
// Function will be called 1 or more times with streams that may fail.
// Retries:
// Function MUST handle errors on the stream by rejecting the promise,
// so that retry logic can pick it up and either retry or fail whatever
// promise it was making (ie, failing extraction, etc.)
//
// The return value of this method is a Promise that resolves the same
// as whatever the streamHandler resolves to.
//
// This should never be overridden by child classes, but it is public.
tarballStream (streamHandler) {
// Only short-circuit via cache if we have everything else we'll need,
// and the user has not expressed a preference for checking online.
const fromCache = (
!this.preferOnline &&
this.integrity &&
this.resolved
) ? streamHandler(this[_tarballFromCache]()).catch(er => {
if (this.isDataCorruptionError(er)) {
log.warn('tarball', `cached data for ${
this.spec
} (${this.integrity}) seems to be corrupted. Refreshing cache.`)
return this.cleanupCached().then(() => {
throw er
})
} else {
throw er
}
}) : null
const fromResolved = er => {
if (er) {
if (!this.isRetriableError(er)) {
throw er
}
log.silly('tarball', `no local data for ${
this.spec
}. Extracting by manifest.`)
}
return this.resolve().then(() => retry(tryAgain =>
streamHandler(this[_istream](this[_tarballFromResolved]()))
.catch(streamErr => {
// Most likely data integrity. A cache ENOENT error is unlikely
// here, since we're definitely not reading from the cache, but it
// IS possible that the fetch subsystem accessed the cache, and the
// entry got blown away or something. Try one more time to be sure.
if (this.isRetriableError(streamErr)) {
log.warn('tarball', `tarball data for ${
this.spec
} (${this.integrity}) seems to be corrupted. Trying again.`)
return this.cleanupCached().then(() => tryAgain(streamErr))
}
throw streamErr
}), { retries: 1, minTimeout: 0, maxTimeout: 0 }))
}
return fromCache ? fromCache.catch(fromResolved) : fromResolved()
}
cleanupCached () {
return cacache.rm.content(this.cache, this.integrity, this.opts)
}
[_empty] (path) {
return getContents({ path, depth: 1 }).then(contents => Promise.all(
contents.map(entry => fs.rm(entry, { recursive: true, force: true }))))
}
async [_mkdir] (dest) {
await this[_empty](dest)
return await fs.mkdir(dest, { recursive: true })
}
// extraction is always the same. the only difference is where
// the tarball comes from.
async extract (dest) {
await this[_mkdir](dest)
return this.tarballStream((tarball) => this[_extract](dest, tarball))
}
[_toFile] (dest) {
return this.tarballStream(str => new Promise((res, rej) => {
const writer = new fsm.WriteStream(dest)
str.on('error', er => writer.emit('error', er))
writer.on('error', er => rej(er))
writer.on('close', () => res({
integrity: this.integrity && String(this.integrity),
resolved: this.resolved,
from: this.from,
}))
str.pipe(writer)
}))
}
// don't use this[_mkdir] because we don't want to rimraf anything
async tarballFile (dest) {
const dir = dirname(dest)
await fs.mkdir(dir, { recursive: true })
return this[_toFile](dest)
}
[_extract] (dest, tarball) {
const extractor = tar.x(this[_tarxOptions]({ cwd: dest }))
const p = new Promise((resolve, reject) => {
extractor.on('end', () => {
resolve({
resolved: this.resolved,
integrity: this.integrity && String(this.integrity),
from: this.from,
})
})
extractor.on('error', er => {
log.warn('tar', er.message)
log.silly('tar', er)
reject(er)
})
tarball.on('error', er => reject(er))
})
tarball.pipe(extractor)
return p
}
// always ensure that entries are at least as permissive as our configured
// dmode/fmode, but never more permissive than the umask allows.
[_entryMode] (path, mode, type) {
const m = /Directory|GNUDumpDir/.test(type) ? this.dmode
: /File$/.test(type) ? this.fmode
: /* istanbul ignore next - should never happen in a pkg */ 0
// make sure package bins are executable
const exe = isPackageBin(this.package, path) ? 0o111 : 0
// always ensure that files are read/writable by the owner
return ((mode | m) & ~this.umask) | exe | 0o600
}
[_tarxOptions] ({ cwd, uid, gid }) {
const sawIgnores = new Set()
return {
cwd,
noChmod: true,
noMtime: true,
filter: (name, entry) => {
if (/Link$/.test(entry.type)) {
return false
}
entry.mode = this[_entryMode](entry.path, entry.mode, entry.type)
// this replicates the npm pack behavior where .gitignore files
// are treated like .npmignore files, but only if a .npmignore
// file is not present.
if (/File$/.test(entry.type)) {
const base = basename(entry.path)
if (base === '.npmignore') {
sawIgnores.add(entry.path)
} else if (base === '.gitignore' && !this.allowGitIgnore) {
// rename, but only if there's not already a .npmignore
const ni = entry.path.replace(/\.gitignore$/, '.npmignore')
if (sawIgnores.has(ni)) {
return false
}
entry.path = ni
}
return true
}
},
strip: 1,
onwarn: /* istanbul ignore next - we can trust that tar logs */
(code, msg, data) => {
log.warn('tar', code, msg)
log.silly('tar', code, msg, data)
},
uid,
gid,
umask: this.umask,
}
}
}
module.exports = FetcherBase
// Child classes
const GitFetcher = require('./git.js')
const RegistryFetcher = require('./registry.js')
const FileFetcher = require('./file.js')
const DirFetcher = require('./dir.js')
const RemoteFetcher = require('./remote.js')
// Get an appropriate fetcher object from a spec and options
FetcherBase.get = (rawSpec, opts = {}) => {
const spec = npa(rawSpec, opts.where)
switch (spec.type) {
case 'git':
return new GitFetcher(spec, opts)
case 'remote':
return new RemoteFetcher(spec, opts)
case 'version':
case 'range':
case 'tag':
case 'alias':
return new RegistryFetcher(spec.subSpec || spec, opts)
case 'file':
return new FileFetcher(spec, opts)
case 'directory':
return new DirFetcher(spec, opts)
default:
throw new TypeError('Unknown spec type: ' + spec.type)
}
}

96
front/app/node_modules/pacote/lib/file.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
const Fetcher = require('./fetcher.js')
const fsm = require('fs-minipass')
const cacache = require('cacache')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
const _exeBins = Symbol('_exeBins')
const { resolve } = require('path')
const fs = require('fs')
const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson')
class FileFetcher extends Fetcher {
constructor (spec, opts) {
super(spec, opts)
// just the fully resolved filename
this.resolved = this.spec.fetchSpec
}
get types () {
return ['file']
}
manifest () {
if (this.package) {
return Promise.resolve(this.package)
}
// have to unpack the tarball for this.
return cacache.tmp.withTmp(this.cache, this.opts, dir =>
this.extract(dir)
.then(() => this[_readPackageJson](dir + '/package.json'))
.then(mani => this.package = {
...mani,
_integrity: this.integrity && String(this.integrity),
_resolved: this.resolved,
_from: this.from,
}))
}
[_exeBins] (pkg, dest) {
if (!pkg.bin) {
return Promise.resolve()
}
return Promise.all(Object.keys(pkg.bin).map(k => new Promise(res => {
const script = resolve(dest, pkg.bin[k])
// Best effort. Ignore errors here, the only result is that
// a bin script is not executable. But if it's missing or
// something, we just leave it for a later stage to trip over
// when we can provide a more useful contextual error.
fs.stat(script, (er, st) => {
if (er) {
return res()
}
const mode = st.mode | 0o111
if (mode === st.mode) {
return res()
}
fs.chmod(script, mode, res)
})
})))
}
extract (dest) {
// if we've already loaded the manifest, then the super got it.
// but if not, read the unpacked manifest and chmod properly.
return super.extract(dest)
.then(result => this.package ? result
: this[_readPackageJson](dest + '/package.json').then(pkg =>
this[_exeBins](pkg, dest)).then(() => result))
}
[_tarballFromResolved] () {
// create a read stream and return it
return new fsm.ReadStream(this.resolved)
}
packument () {
// simulate based on manifest
return this.manifest().then(mani => ({
name: mani.name,
'dist-tags': {
[this.defaultTag]: mani.version,
},
versions: {
[mani.version]: {
...mani,
dist: {
tarball: `file:${this.resolved}`,
integrity: this.integrity && String(this.integrity),
},
},
},
}))
}
}
module.exports = FileFetcher

327
front/app/node_modules/pacote/lib/git.js generated vendored Normal file
View File

@@ -0,0 +1,327 @@
const Fetcher = require('./fetcher.js')
const FileFetcher = require('./file.js')
const RemoteFetcher = require('./remote.js')
const DirFetcher = require('./dir.js')
const hashre = /^[a-f0-9]{40}$/
const git = require('@npmcli/git')
const pickManifest = require('npm-pick-manifest')
const npa = require('npm-package-arg')
const Minipass = require('minipass')
const cacache = require('cacache')
const log = require('proc-log')
const npm = require('./util/npm.js')
const _resolvedFromRepo = Symbol('_resolvedFromRepo')
const _resolvedFromHosted = Symbol('_resolvedFromHosted')
const _resolvedFromClone = Symbol('_resolvedFromClone')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
const _addGitSha = Symbol('_addGitSha')
const addGitSha = require('./util/add-git-sha.js')
const _clone = Symbol('_clone')
const _cloneHosted = Symbol('_cloneHosted')
const _cloneRepo = Symbol('_cloneRepo')
const _setResolvedWithSha = Symbol('_setResolvedWithSha')
const _prepareDir = Symbol('_prepareDir')
const _readPackageJson = Symbol.for('package.Fetcher._readPackageJson')
// get the repository url.
// prefer https if there's auth, since ssh will drop that.
// otherwise, prefer ssh if available (more secure).
// We have to add the git+ back because npa suppresses it.
const repoUrl = (h, opts) =>
h.sshurl && !(h.https && h.auth) && addGitPlus(h.sshurl(opts)) ||
h.https && addGitPlus(h.https(opts))
// add git+ to the url, but only one time.
const addGitPlus = url => url && `git+${url}`.replace(/^(git\+)+/, 'git+')
class GitFetcher extends Fetcher {
constructor (spec, opts) {
super(spec, opts)
// we never want to compare integrity for git dependencies: npm/rfcs#525
if (this.opts.integrity) {
delete this.opts.integrity
log.warn(`skipping integrity check for git dependency ${this.spec.fetchSpec}`)
}
this.resolvedRef = null
if (this.spec.hosted) {
this.from = this.spec.hosted.shortcut({ noCommittish: false })
}
// shortcut: avoid full clone when we can go straight to the tgz
// if we have the full sha and it's a hosted git platform
if (this.spec.gitCommittish && hashre.test(this.spec.gitCommittish)) {
this.resolvedSha = this.spec.gitCommittish
// use hosted.tarball() when we shell to RemoteFetcher later
this.resolved = this.spec.hosted
? repoUrl(this.spec.hosted, { noCommittish: false })
: this.spec.rawSpec
} else {
this.resolvedSha = ''
}
this.Arborist = opts.Arborist || null
}
// just exposed to make it easier to test all the combinations
static repoUrl (hosted, opts) {
return repoUrl(hosted, opts)
}
get types () {
return ['git']
}
resolve () {
// likely a hosted git repo with a sha, so get the tarball url
// but in general, no reason to resolve() more than necessary!
if (this.resolved) {
return super.resolve()
}
// fetch the git repo and then look at the current hash
const h = this.spec.hosted
// try to use ssh, fall back to git.
return h ? this[_resolvedFromHosted](h)
: this[_resolvedFromRepo](this.spec.fetchSpec)
}
// first try https, since that's faster and passphrase-less for
// public repos, and supports private repos when auth is provided.
// Fall back to SSH to support private repos
// NB: we always store the https url in resolved field if auth
// is present, otherwise ssh if the hosted type provides it
[_resolvedFromHosted] (hosted) {
return this[_resolvedFromRepo](hosted.https && hosted.https())
.catch(er => {
// Throw early since we know pathspec errors will fail again if retried
if (er instanceof git.errors.GitPathspecError) {
throw er
}
const ssh = hosted.sshurl && hosted.sshurl()
// no fallthrough if we can't fall through or have https auth
if (!ssh || hosted.auth) {
throw er
}
return this[_resolvedFromRepo](ssh)
})
}
[_resolvedFromRepo] (gitRemote) {
// XXX make this a custom error class
if (!gitRemote) {
return Promise.reject(new Error(`No git url for ${this.spec}`))
}
const gitRange = this.spec.gitRange
const name = this.spec.name
return git.revs(gitRemote, this.opts).then(remoteRefs => {
return gitRange ? pickManifest({
versions: remoteRefs.versions,
'dist-tags': remoteRefs['dist-tags'],
name,
}, gitRange, this.opts)
: this.spec.gitCommittish ?
remoteRefs.refs[this.spec.gitCommittish] ||
remoteRefs.refs[remoteRefs.shas[this.spec.gitCommittish]]
: remoteRefs.refs.HEAD // no git committish, get default head
}).then(revDoc => {
// the committish provided isn't in the rev list
// things like HEAD~3 or @yesterday can land here.
if (!revDoc || !revDoc.sha) {
return this[_resolvedFromClone]()
}
this.resolvedRef = revDoc
this.resolvedSha = revDoc.sha
this[_addGitSha](revDoc.sha)
return this.resolved
})
}
[_setResolvedWithSha] (withSha) {
// we haven't cloned, so a tgz download is still faster
// of course, if it's not a known host, we can't do that.
this.resolved = !this.spec.hosted ? withSha
: repoUrl(npa(withSha).hosted, { noCommittish: false })
}
// when we get the git sha, we affix it to our spec to build up
// either a git url with a hash, or a tarball download URL
[_addGitSha] (sha) {
this[_setResolvedWithSha](addGitSha(this.spec, sha))
}
[_resolvedFromClone] () {
// do a full or shallow clone, then look at the HEAD
// kind of wasteful, but no other option, really
return this[_clone](dir => this.resolved)
}
[_prepareDir] (dir) {
return this[_readPackageJson](dir + '/package.json').then(mani => {
// no need if we aren't going to do any preparation.
const scripts = mani.scripts
if (!mani.workspaces && (!scripts || !(
scripts.postinstall ||
scripts.build ||
scripts.preinstall ||
scripts.install ||
scripts.prepack ||
scripts.prepare))) {
return
}
// to avoid cases where we have an cycle of git deps that depend
// on one another, we only ever do preparation for one instance
// of a given git dep along the chain of installations.
// Note that this does mean that a dependency MAY in theory end up
// trying to run its prepare script using a dependency that has not
// been properly prepared itself, but that edge case is smaller
// and less hazardous than a fork bomb of npm and git commands.
const noPrepare = !process.env._PACOTE_NO_PREPARE_ ? []
: process.env._PACOTE_NO_PREPARE_.split('\n')
if (noPrepare.includes(this.resolved)) {
log.info('prepare', 'skip prepare, already seen', this.resolved)
return
}
noPrepare.push(this.resolved)
// the DirFetcher will do its own preparation to run the prepare scripts
// All we have to do is put the deps in place so that it can succeed.
return npm(
this.npmBin,
[].concat(this.npmInstallCmd).concat(this.npmCliConfig),
dir,
{ ...process.env, _PACOTE_NO_PREPARE_: noPrepare.join('\n') },
{ message: 'git dep preparation failed' }
)
})
}
[_tarballFromResolved] () {
const stream = new Minipass()
stream.resolved = this.resolved
stream.from = this.from
// check it out and then shell out to the DirFetcher tarball packer
this[_clone](dir => this[_prepareDir](dir)
.then(() => new Promise((res, rej) => {
if (!this.Arborist) {
throw new Error('GitFetcher requires an Arborist constructor to pack a tarball')
}
const df = new DirFetcher(`file:${dir}`, {
...this.opts,
Arborist: this.Arborist,
resolved: null,
integrity: null,
})
const dirStream = df[_tarballFromResolved]()
dirStream.on('error', rej)
dirStream.on('end', res)
dirStream.pipe(stream)
}))).catch(
/* istanbul ignore next: very unlikely and hard to test */
er => stream.emit('error', er)
)
return stream
}
// clone a git repo into a temp folder (or fetch and unpack if possible)
// handler accepts a directory, and returns a promise that resolves
// when we're done with it, at which point, cacache deletes it
//
// TODO: after cloning, create a tarball of the folder, and add to the cache
// with cacache.put.stream(), using a key that's deterministic based on the
// spec and repo, so that we don't ever clone the same thing multiple times.
[_clone] (handler, tarballOk = true) {
const o = { tmpPrefix: 'git-clone' }
const ref = this.resolvedSha || this.spec.gitCommittish
const h = this.spec.hosted
const resolved = this.resolved
// can be set manually to false to fall back to actual git clone
tarballOk = tarballOk &&
h && resolved === repoUrl(h, { noCommittish: false }) && h.tarball
return cacache.tmp.withTmp(this.cache, o, async tmp => {
// if we're resolved, and have a tarball url, shell out to RemoteFetcher
if (tarballOk) {
const nameat = this.spec.name ? `${this.spec.name}@` : ''
return new RemoteFetcher(h.tarball({ noCommittish: false }), {
...this.opts,
allowGitIgnore: true,
pkgid: `git:${nameat}${this.resolved}`,
resolved: this.resolved,
integrity: null, // it'll always be different, if we have one
}).extract(tmp).then(() => handler(tmp), er => {
// fall back to ssh download if tarball fails
if (er.constructor.name.match(/^Http/)) {
return this[_clone](handler, false)
} else {
throw er
}
})
}
const sha = await (
h ? this[_cloneHosted](ref, tmp)
: this[_cloneRepo](this.spec.fetchSpec, ref, tmp)
)
this.resolvedSha = sha
if (!this.resolved) {
await this[_addGitSha](sha)
}
return handler(tmp)
})
}
// first try https, since that's faster and passphrase-less for
// public repos, and supports private repos when auth is provided.
// Fall back to SSH to support private repos
// NB: we always store the https url in resolved field if auth
// is present, otherwise ssh if the hosted type provides it
[_cloneHosted] (ref, tmp) {
const hosted = this.spec.hosted
return this[_cloneRepo](hosted.https({ noCommittish: true }), ref, tmp)
.catch(er => {
// Throw early since we know pathspec errors will fail again if retried
if (er instanceof git.errors.GitPathspecError) {
throw er
}
const ssh = hosted.sshurl && hosted.sshurl({ noCommittish: true })
// no fallthrough if we can't fall through or have https auth
if (!ssh || hosted.auth) {
throw er
}
return this[_cloneRepo](ssh, ref, tmp)
})
}
[_cloneRepo] (repo, ref, tmp) {
const { opts, spec } = this
return git.clone(repo, ref, tmp, { ...opts, spec })
}
manifest () {
if (this.package) {
return Promise.resolve(this.package)
}
return this.spec.hosted && this.resolved
? FileFetcher.prototype.manifest.apply(this)
: this[_clone](dir =>
this[_readPackageJson](dir + '/package.json')
.then(mani => this.package = {
...mani,
_resolved: this.resolved,
_from: this.from,
}))
}
packument () {
return FileFetcher.prototype.packument.apply(this)
}
}
module.exports = GitFetcher

23
front/app/node_modules/pacote/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
const { get } = require('./fetcher.js')
const GitFetcher = require('./git.js')
const RegistryFetcher = require('./registry.js')
const FileFetcher = require('./file.js')
const DirFetcher = require('./dir.js')
const RemoteFetcher = require('./remote.js')
module.exports = {
GitFetcher,
RegistryFetcher,
FileFetcher,
DirFetcher,
RemoteFetcher,
resolve: (spec, opts) => get(spec, opts).resolve(),
extract: (spec, dest, opts) => get(spec, opts).extract(dest),
manifest: (spec, opts) => get(spec, opts).manifest(),
tarball: (spec, opts) => get(spec, opts).tarball(),
packument: (spec, opts) => get(spec, opts).packument(),
}
module.exports.tarball.stream = (spec, handler, opts) =>
get(spec, opts).tarballStream(handler)
module.exports.tarball.file = (spec, dest, opts) =>
get(spec, opts).tarballFile(dest)

228
front/app/node_modules/pacote/lib/registry.js generated vendored Normal file
View File

@@ -0,0 +1,228 @@
const Fetcher = require('./fetcher.js')
const RemoteFetcher = require('./remote.js')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
const pacoteVersion = require('../package.json').version
const removeTrailingSlashes = require('./util/trailing-slashes.js')
const rpj = require('read-package-json-fast')
const pickManifest = require('npm-pick-manifest')
const ssri = require('ssri')
const crypto = require('crypto')
// Corgis are cute. 🐕🐶
const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
const fullDoc = 'application/json'
const fetch = require('npm-registry-fetch')
const _headers = Symbol('_headers')
class RegistryFetcher extends Fetcher {
constructor (spec, opts) {
super(spec, opts)
// you usually don't want to fetch the same packument multiple times in
// the span of a given script or command, no matter how many pacote calls
// are made, so this lets us avoid doing that. It's only relevant for
// registry fetchers, because other types simulate their packument from
// the manifest, which they memoize on this.package, so it's very cheap
// already.
this.packumentCache = this.opts.packumentCache || null
this.registry = fetch.pickRegistry(spec, opts)
this.packumentUrl = removeTrailingSlashes(this.registry) + '/' +
this.spec.escapedName
const parsed = new URL(this.registry)
const regKey = `//${parsed.host}${parsed.pathname}`
// unlike the nerf-darted auth keys, this one does *not* allow a mismatch
// of trailing slashes. It must match exactly.
if (this.opts[`${regKey}:_keys`]) {
this.registryKeys = this.opts[`${regKey}:_keys`]
}
// XXX pacote <=9 has some logic to ignore opts.resolved if
// the resolved URL doesn't go to the same registry.
// Consider reproducing that here, to throw away this.resolved
// in that case.
}
async resolve () {
// fetching the manifest sets resolved and (if present) integrity
await this.manifest()
if (!this.resolved) {
throw Object.assign(
new Error('Invalid package manifest: no `dist.tarball` field'),
{ package: this.spec.toString() }
)
}
return this.resolved
}
[_headers] () {
return {
// npm will override UA, but ensure that we always send *something*
'user-agent': this.opts.userAgent ||
`pacote/${pacoteVersion} node/${process.version}`,
...(this.opts.headers || {}),
'pacote-version': pacoteVersion,
'pacote-req-type': 'packument',
'pacote-pkg-id': `registry:${this.spec.name}`,
accept: this.fullMetadata ? fullDoc : corgiDoc,
}
}
async packument () {
// note this might be either an in-flight promise for a request,
// or the actual packument, but we never want to make more than
// one request at a time for the same thing regardless.
if (this.packumentCache && this.packumentCache.has(this.packumentUrl)) {
return this.packumentCache.get(this.packumentUrl)
}
// npm-registry-fetch the packument
// set the appropriate header for corgis if fullMetadata isn't set
// return the res.json() promise
try {
const res = await fetch(this.packumentUrl, {
...this.opts,
headers: this[_headers](),
spec: this.spec,
// never check integrity for packuments themselves
integrity: null,
})
const packument = await res.json()
packument._contentLength = +res.headers.get('content-length')
if (this.packumentCache) {
this.packumentCache.set(this.packumentUrl, packument)
}
return packument
} catch (err) {
if (this.packumentCache) {
this.packumentCache.delete(this.packumentUrl)
}
if (err.code !== 'E404' || this.fullMetadata) {
throw err
}
// possible that corgis are not supported by this registry
this.fullMetadata = true
return this.packument()
}
}
async manifest () {
if (this.package) {
return this.package
}
const packument = await this.packument()
let mani = await pickManifest(packument, this.spec.fetchSpec, {
...this.opts,
defaultTag: this.defaultTag,
before: this.before,
})
mani = rpj.normalize(mani)
/* XXX add ETARGET and E403 revalidation of cached packuments here */
// add _resolved and _integrity from dist object
const { dist } = mani
if (dist) {
this.resolved = mani._resolved = dist.tarball
mani._from = this.from
const distIntegrity = dist.integrity ? ssri.parse(dist.integrity)
: dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', { ...this.opts })
: null
if (distIntegrity) {
if (this.integrity && !this.integrity.match(distIntegrity)) {
// only bork if they have algos in common.
// otherwise we end up breaking if we have saved a sha512
// previously for the tarball, but the manifest only
// provides a sha1, which is possible for older publishes.
// Otherwise, this is almost certainly a case of holding it
// wrong, and will result in weird or insecure behavior
// later on when building package tree.
for (const algo of Object.keys(this.integrity)) {
if (distIntegrity[algo]) {
throw Object.assign(new Error(
`Integrity checksum failed when using ${algo}: ` +
`wanted ${this.integrity} but got ${distIntegrity}.`
), { code: 'EINTEGRITY' })
}
}
}
// made it this far, the integrity is worthwhile. accept it.
// the setter here will take care of merging it into what we already
// had.
this.integrity = distIntegrity
}
}
if (this.integrity) {
mani._integrity = String(this.integrity)
if (dist.signatures) {
if (this.opts.verifySignatures) {
// validate and throw on error, then set _signatures
const message = `${mani._id}:${mani._integrity}`
for (const signature of dist.signatures) {
const publicKey = this.registryKeys &&
this.registryKeys.filter(key => (key.keyid === signature.keyid))[0]
if (!publicKey) {
throw Object.assign(new Error(
`${mani._id} has a registry signature with keyid: ${signature.keyid} ` +
'but no corresponding public key can be found'
), { code: 'EMISSINGSIGNATUREKEY' })
}
const validPublicKey =
!publicKey.expires || (Date.parse(publicKey.expires) > Date.now())
if (!validPublicKey) {
throw Object.assign(new Error(
`${mani._id} has a registry signature with keyid: ${signature.keyid} ` +
`but the corresponding public key has expired ${publicKey.expires}`
), { code: 'EEXPIREDSIGNATUREKEY' })
}
const verifier = crypto.createVerify('SHA256')
verifier.write(message)
verifier.end()
const valid = verifier.verify(
publicKey.pemkey,
signature.sig,
'base64'
)
if (!valid) {
throw Object.assign(new Error(
`${mani._id} has an invalid registry signature with ` +
`keyid: ${publicKey.keyid} and signature: ${signature.sig}`
), {
code: 'EINTEGRITYSIGNATURE',
keyid: publicKey.keyid,
signature: signature.sig,
resolved: mani._resolved,
integrity: mani._integrity,
})
}
}
mani._signatures = dist.signatures
} else {
mani._signatures = dist.signatures
}
}
}
this.package = mani
return this.package
}
[_tarballFromResolved] () {
// we use a RemoteFetcher to get the actual tarball stream
return new RemoteFetcher(this.resolved, {
...this.opts,
resolved: this.resolved,
pkgid: `registry:${this.spec.name}@${this.resolved}`,
})[_tarballFromResolved]()
}
get types () {
return [
'tag',
'version',
'range',
]
}
}
module.exports = RegistryFetcher

91
front/app/node_modules/pacote/lib/remote.js generated vendored Normal file
View File

@@ -0,0 +1,91 @@
const Fetcher = require('./fetcher.js')
const FileFetcher = require('./file.js')
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
const pacoteVersion = require('../package.json').version
const fetch = require('npm-registry-fetch')
const Minipass = require('minipass')
const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches')
const _headers = Symbol('_headers')
class RemoteFetcher extends Fetcher {
constructor (spec, opts) {
super(spec, opts)
this.resolved = this.spec.fetchSpec
const resolvedURL = new URL(this.resolved)
if (this.replaceRegistryHost !== 'never'
&& (this.replaceRegistryHost === 'always'
|| this.replaceRegistryHost === resolvedURL.host)) {
this.resolved = new URL(resolvedURL.pathname, this.registry).href
}
// nam is a fermented pork sausage that is good to eat
const nameat = this.spec.name ? `${this.spec.name}@` : ''
this.pkgid = opts.pkgid ? opts.pkgid : `remote:${nameat}${this.resolved}`
}
// Don't need to cache tarball fetches in pacote, because make-fetch-happen
// will write into cacache anyway.
get [_cacheFetches] () {
return false
}
[_tarballFromResolved] () {
const stream = new Minipass()
stream.hasIntegrityEmitter = true
const fetchOpts = {
...this.opts,
headers: this[_headers](),
spec: this.spec,
integrity: this.integrity,
algorithms: [this.pickIntegrityAlgorithm()],
}
// eslint-disable-next-line promise/always-return
fetch(this.resolved, fetchOpts).then(res => {
res.body.on('error',
/* istanbul ignore next - exceedingly rare and hard to simulate */
er => stream.emit('error', er)
)
res.body.on('integrity', i => {
this.integrity = i
stream.emit('integrity', i)
})
res.body.pipe(stream)
}).catch(er => stream.emit('error', er))
return stream
}
[_headers] () {
return {
// npm will override this, but ensure that we always send *something*
'user-agent': this.opts.userAgent ||
`pacote/${pacoteVersion} node/${process.version}`,
...(this.opts.headers || {}),
'pacote-version': pacoteVersion,
'pacote-req-type': 'tarball',
'pacote-pkg-id': this.pkgid,
...(this.integrity ? { 'pacote-integrity': String(this.integrity) }
: {}),
...(this.opts.headers || {}),
}
}
get types () {
return ['remote']
}
// getting a packument and/or manifest is the same as with a file: spec.
// unpack the tarball stream, and then read from the package.json file.
packument () {
return FileFetcher.prototype.packument.apply(this)
}
manifest () {
return FileFetcher.prototype.manifest.apply(this)
}
}
module.exports = RemoteFetcher

15
front/app/node_modules/pacote/lib/util/add-git-sha.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
// add a sha to a git remote url spec
const addGitSha = (spec, sha) => {
if (spec.hosted) {
const h = spec.hosted
const opt = { noCommittish: true }
const base = h.https && h.auth ? h.https(opt) : h.shortcut(opt)
return `${base}#${sha}`
} else {
// don't use new URL for this, because it doesn't handle scp urls
return spec.rawSpec.replace(/#.*$/, '') + `#${sha}`
}
}
module.exports = addGitSha

12
front/app/node_modules/pacote/lib/util/cache-dir.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
const os = require('os')
const { resolve } = require('path')
module.exports = (fakePlatform = false) => {
const temp = os.tmpdir()
const uidOrPid = process.getuid ? process.getuid() : process.pid
const home = os.homedir() || resolve(temp, 'npm-' + uidOrPid)
const platform = fakePlatform || process.platform
const cacheExtra = platform === 'win32' ? 'npm-cache' : '.npm'
const cacheRoot = (platform === 'win32' && process.env.LOCALAPPDATA) || home
return resolve(cacheRoot, cacheExtra, '_cacache')
}

View File

@@ -0,0 +1,25 @@
// Function to determine whether a path is in the package.bin set.
// Used to prevent issues when people publish a package from a
// windows machine, and then install with --no-bin-links.
//
// Note: this is not possible in remote or file fetchers, since
// we don't have the manifest until AFTER we've unpacked. But the
// main use case is registry fetching with git a distant second,
// so that's an acceptable edge case to not handle.
const binObj = (name, bin) =>
typeof bin === 'string' ? { [name]: bin } : bin
const hasBin = (pkg, path) => {
const bin = binObj(pkg.name, pkg.bin)
const p = path.replace(/^[^\\/]*\//, '')
for (const kv of Object.entries(bin)) {
if (kv[1] === p) {
return true
}
}
return false
}
module.exports = (pkg, path) =>
pkg && pkg.bin ? hasBin(pkg, path) : false

14
front/app/node_modules/pacote/lib/util/npm.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
// run an npm command
const spawn = require('@npmcli/promise-spawn')
module.exports = (npmBin, npmCommand, cwd, env, extra) => {
const isJS = npmBin.endsWith('.js')
const cmd = isJS ? process.execPath : npmBin
const args = (isJS ? [npmBin] : []).concat(npmCommand)
// when installing to run the `prepare` script for a git dep, we need
// to ensure that we don't run into a cycle of checking out packages
// in temp directories. this lets us link previously-seen repos that
// are also being prepared.
return spawn(cmd, args, { cwd, env }, extra)
}

View File

@@ -0,0 +1,31 @@
const isPackageBin = require('./is-package-bin.js')
const tarCreateOptions = manifest => ({
cwd: manifest._resolved,
prefix: 'package/',
portable: true,
gzip: {
// forcing the level to 9 seems to avoid some
// platform specific optimizations that cause
// integrity mismatch errors due to differing
// end results after compression
level: 9,
},
// ensure that package bins are always executable
// Note that npm-packlist is already filtering out
// anything that is not a regular file, ignored by
// .npmignore or package.json "files", etc.
filter: (path, stat) => {
if (isPackageBin(manifest, path)) {
stat.mode |= 0o111
}
return true
},
// Provide a specific date in the 1980s for the benefit of zip,
// which is confounded by files dated at the Unix epoch 0.
mtime: new Date('1985-10-26T08:15:00.000Z'),
})
module.exports = tarCreateOptions

View File

@@ -0,0 +1,10 @@
const removeTrailingSlashes = (input) => {
// in order to avoid regexp redos detection
let output = input
while (output.endsWith('/')) {
output = output.slice(0, -1)
}
return output
}
module.exports = removeTrailingSlashes

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/**"
]
}
}

77
front/app/node_modules/pacote/package.json generated vendored Normal file
View File

@@ -0,0 +1,77 @@
{
"name": "pacote",
"version": "15.0.6",
"description": "JavaScript package downloader",
"author": "GitHub Inc.",
"bin": {
"pacote": "lib/bin.js"
},
"license": "ISC",
"main": "lib/index.js",
"scripts": {
"test": "tap",
"snap": "tap",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
"posttest": "npm run lint",
"template-oss-apply": "template-oss-apply --force"
},
"tap": {
"timeout": 300,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"devDependencies": {
"@npmcli/arborist": "^6.0.0 || ^6.0.0-pre.0",
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.8.0",
"hosted-git-info": "^6.0.0",
"mutate-fs": "^2.1.1",
"nock": "^13.2.4",
"npm-registry-mock": "^1.3.2",
"tap": "^16.0.1"
},
"files": [
"bin/",
"lib/"
],
"keywords": [
"packages",
"npm",
"git"
],
"dependencies": {
"@npmcli/git": "^4.0.0",
"@npmcli/installed-package-contents": "^2.0.1",
"@npmcli/promise-spawn": "^6.0.1",
"@npmcli/run-script": "^6.0.0",
"cacache": "^17.0.0",
"fs-minipass": "^2.1.0",
"minipass": "^3.1.6",
"npm-package-arg": "^10.0.0",
"npm-packlist": "^7.0.0",
"npm-pick-manifest": "^8.0.0",
"npm-registry-fetch": "^14.0.0",
"proc-log": "^3.0.0",
"promise-retry": "^2.0.1",
"read-package-json": "^6.0.0",
"read-package-json-fast": "^3.0.0",
"ssri": "^10.0.0",
"tar": "^6.1.11"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/pacote.git"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.8.0",
"windowsCI": false
}
}