deps: upgrade npm to 7.7.4

PR-URL: https://github.com/nodejs/node/pull/37897
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Ruy Adorno 2021-03-24 17:25:32 -04:00 committed by Rich Trott
parent 42dc4d14cd
commit ce300d6f76
82 changed files with 1001 additions and 2204 deletions

2
deps/npm/AUTHORS vendored
View File

@ -765,3 +765,5 @@ Jan Sepke <625043+jansepke@users.noreply.github.com>
Augusto Moura <augusto.borgesm@gmail.com>
Eric Chow <eric.zjp.chow@gmail.com>
kbayrhammer <klaus.bayrhammer@redbull.com>
James Chen-Smith <jameschensmith@gmail.com>
Yash Singh <saiansh2525@gmail.com>

77
deps/npm/CHANGELOG.md vendored
View File

@ -1,3 +1,80 @@
## v7.7.4 (2021-03-24)
### BUG FIXES
* [`200bee74b`](https://github.com/npm/cli/commit/200bee74b31a738687446b7b535cac67b1c582fd)
[#2951](https://github.com/npm/cli/issues/2951)
fix(config): accept explicit `production=false`
([@wraithgar](https://github.com/wraithgar))
* [`7b45e9df6`](https://github.com/npm/cli/commit/7b45e9df6102c7bd6e403d1fdc9939581c38f546)
[#2950](https://github.com/npm/cli/issues/2950)
warn if using workspaces config options in `npm config`
([@ruyadorno](https://github.com/ruyadorno))
## v7.7.3 (2021-03-24)
### BUG FIXES
* [`c76f04ac2`](https://github.com/npm/cli/commit/c76f04ac28ddf2ae4df4b3ce0aec684a118de1b5)
[#2925](https://github.com/npm/cli/issues/2925)
fix(set-script): add completion
([@Yash-Singh1](https://github.com/Yash-Singh1))
* [`0379eab69`](https://github.com/npm/cli/commit/0379eab698b78ae4aa89bbe2043607f420e52f11)
[#2929](https://github.com/npm/cli/issues/2929)
fix(install): ignore auditLevel
`npm install` should not be affected by the `auditLevel` config, as the
results of audit do not change its exit status.
([@wraithgar](https://github.com/wraithgar))
* [`98efadeb4`](https://github.com/npm/cli/commit/98efadeb4b2ae9289f14ed6f42a169230faf7239)
[#2923](https://github.com/npm/cli/issues/2923)
fix(audit-level): add `info` audit level
This is a valid level but wasn't configured to be allowed.
Also added this param to the usage output for `npm audit`
([@wraithgar](https://github.com/wraithgar))
* [`e8d2adcf4`](https://github.com/npm/cli/commit/e8d2adcf40ad63030f844c9aa44c6d16e2146797)
[#2945](https://github.com/npm/cli/issues/2945)
config should not error when workspaces are configured
([@nlf](https://github.com/nlf))
* [`aba2bc623`](https://github.com/npm/cli/commit/aba2bc623ea99e563b1b15b81dbb4ba94f86fe4c)
[#2944](https://github.com/npm/cli/issues/2944)
fix(progress): re-add progress bar to reify
The logger was no longer in flatOptions, we pass it in explicitly now
([@wraithgar](https://github.com/wraithgar))
* [`877b4ed29`](https://github.com/npm/cli/commit/877b4ed2925c97b5249a4d33575420dda64f7339)
[#2946](https://github.com/npm/cli/issues/2946)
fix(flatOptions): re-add `_auth`
This was not being added to flatOptions, and things like
`npm-registry-fetch` are looking for it.
([@wraithgar](https://github.com/wraithgar))
## v7.7.2 (2021-03-24)
### BUG FIXES
* [`a4df2b98d`](https://github.com/npm/cli/commit/a4df2b98d89429b19cd29b5fc895cdbfc0a6bd78)
[#2942](https://github.com/npm/cli/issues/2942)
Restore --dev flag, unify --omit flatteners
([@isaacs](https://github.com/isaacs))
### DEPENDENCIES
* [`2cbfaac0e`](https://github.com/npm/cli/commit/2cbfaac0ecd5810316f6d76168ed9618bd11bf3a)
`hosted-git-info@4.0.2`
* [#83](https://github.com/npm/hosted-git-info/pull/83) Do not parse
urls for gitlab
([@nlf](https://github.com/nlf))
## v7.7.1 (2021-03-24)
### BUG FIXES
* [`543b0e39b`](https://github.com/npm/cli/commit/543b0e39bcb94fc408804b01ca9c0d7b960b2681)
[#2930](https://github.com/npm/cli/issues/2930)
fix(uninstall): use correct local prefix
([@jameschensmith](https://github.com/jameschensmith))
* [`dce4960ef`](https://github.com/npm/cli/commit/dce4960ef6d52af128affe7755b2ca72de913b6c)
[#2932](https://github.com/npm/cli/issues/2932)
fix(config): flatten savePrefix properly
([@wraithgar](https://github.com/wraithgar))
## v7.7.0 (2021-03-23)
### FEATURES

View File

@ -21,3 +21,4 @@ duplications, without actually changing the package tree.
* [npm ls](/cli-commands/ls)
* [npm update](/cli-commands/update)
* [npm install](/cli-commands/install)

View File

@ -185,7 +185,7 @@ registry and all registries configured for scopes. See the documentation for
#### `audit-level`
* Default: null
* Type: "low", "moderate", "high", "critical", "none", or null
* Type: "info", "low", "moderate", "high", "critical", "none", or null
The minimum level of vulnerability for `npm audit` to exit with a non-zero
exit code.
@ -1382,6 +1382,14 @@ What authentication strategy to use with `adduser`/`login`.
`--cache-min=9999 (or bigger)` is an alias for `--prefer-offline`.
#### `dev`
* Default: false
* Type: Boolean
* DEPRECATED: Please use --include=dev instead.
Alias for `--include=dev`.
#### `init.author.email`
* Default: ""
@ -1451,8 +1459,8 @@ Alias for --include=optional or --omit=optional
#### `production`
* Default: false
* Type: Boolean
* Default: null
* Type: null or Boolean
* DEPRECATED: Use `--omit=dev` instead.
Alias for `--omit=dev`

View File

@ -159,7 +159,7 @@ tree at all, use <a href="../commands/npm-explain.html"><code>npm explain</code>
the results to only the paths to the packages named. Note that nested
packages will <em>also</em> show the paths to the specified packages. For
example, running <code>npm ls promzard</code> in npms source tree will show:</p>
<pre lang="bash"><code>npm@7.7.0 /path/to/npm
<pre lang="bash"><code>npm@7.7.4 /path/to/npm
└─┬ init-package-json@0.0.4
└── promzard@0.1.5
</code></pre>

View File

@ -148,7 +148,7 @@ npm command-line interface
<pre lang="bash"><code>npm &lt;command&gt; [args]
</code></pre>
<h3 id="version">Version</h3>
<p>7.7.0</p>
<p>7.7.4</p>
<h3 id="description">Description</h3>
<p>npm is the package manager for the Node JavaScript platform. It puts
modules in place so that node can find them, and manages dependency

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,7 @@ class Audit extends BaseCommand {
/* istanbul ignore next - see test/lib/load-all-commands.js */
static get params () {
return [
'audit-level',
'dry-run',
'force',
'json',

11
deps/npm/lib/ci.js vendored
View File

@ -42,8 +42,14 @@ class CI extends BaseCommand {
}
const where = this.npm.prefix
const arb = new Arborist({ ...this.npm.flatOptions, path: where })
const opts = {
...this.npm.flatOptions,
path: where,
log: this.npm.log,
save: false, // npm ci should never modify the lockfile or package.json
}
const arb = new Arborist(opts)
await Promise.all([
arb.loadVirtual().catch(er => {
log.verbose('loadVirtual', er.stack)
@ -55,8 +61,7 @@ class CI extends BaseCommand {
}),
removeNodeModules(where),
])
// npm ci should never modify the lockfile or package.json
await arb.reify({ ...this.npm.flatOptions, save: false })
await arb.reify(opts)
const ignoreScripts = this.npm.config.get('ignore-scripts')
// run the same set of scripts that `npm install` runs.

View File

@ -88,6 +88,11 @@ class Config extends BaseCommand {
this.config(args).then(() => cb()).catch(cb)
}
execWorkspaces (args, filters, cb) {
this.npm.log.warn('config', 'This command does not support workspaces.')
this.exec(args, cb)
}
async config ([action, ...args]) {
this.npm.log.disableProgress()
try {

View File

@ -30,6 +30,7 @@ class Dedupe extends BaseCommand {
const where = this.npm.prefix
const opts = {
...this.npm.flatOptions,
log: this.npm.log,
path: where,
dryRun,
}

12
deps/npm/lib/exec.js vendored
View File

@ -175,7 +175,11 @@ class Exec extends BaseCommand {
if (needInstall) {
const installDir = this.cacheInstallDir(packages)
await mkdirp(installDir)
const arb = new Arborist({ ...this.npm.flatOptions, path: installDir })
const arb = new Arborist({
...this.npm.flatOptions,
log: this.npm.log,
path: installDir,
})
const tree = await arb.loadActual()
// at this point, we have to ensure that we get the exact same
@ -212,7 +216,11 @@ class Exec extends BaseCommand {
throw new Error('canceled')
}
}
await arb.reify({ ...this.npm.flatOptions, add })
await arb.reify({
...this.npm.flatOptions,
log: this.npm.log,
add,
})
}
pathArr.unshift(resolve(installDir, 'node_modules/.bin'))
}

View File

@ -126,15 +126,16 @@ class Install extends BaseCommand {
if (this.npm.config.get('dev'))
log.warn('install', 'Usage of the `--dev` option is deprecated. Use `--include=dev` instead.')
const arb = new Arborist({
const opts = {
...this.npm.flatOptions,
log: this.npm.log,
auditLevel: null,
path: where,
})
await arb.reify({
...this.npm.flatOptions,
add: args,
})
}
const arb = new Arborist(opts)
await arb.reify(opts)
if (!args.length && !isGlobalInstall && !ignoreScripts) {
const scriptShell = this.npm.config.get('script-shell') || undefined
const scripts = [

View File

@ -66,6 +66,7 @@ class Link extends BaseCommand {
const globalOpts = {
...this.npm.flatOptions,
path: globalTop,
log: this.npm.log,
global: true,
prune: false,
}
@ -113,12 +114,14 @@ class Link extends BaseCommand {
// reify all the pending names as symlinks there
const localArb = new Arborist({
...this.npm.flatOptions,
log: this.npm.log,
path: this.npm.prefix,
save,
})
await localArb.reify({
...this.npm.flatOptions,
path: this.npm.prefix,
log: this.npm.log,
add: names.map(l => `file:${resolve(globalTop, 'node_modules', l)}`),
save,
})
@ -131,9 +134,13 @@ class Link extends BaseCommand {
const arb = new Arborist({
...this.npm.flatOptions,
path: globalTop,
log: this.npm.log,
global: true,
})
await arb.reify({ add: [`file:${this.npm.prefix}`] })
await arb.reify({
add: [`file:${this.npm.prefix}`],
log: this.npm.log,
})
await reifyFinish(this.npm, arb)
}

View File

@ -30,11 +30,13 @@ class Prune extends BaseCommand {
async prune () {
const where = this.npm.prefix
const arb = new Arborist({
const opts = {
...this.npm.flatOptions,
path: where,
})
await arb.prune(this.npm.flatOptions)
log: this.npm.log,
}
const arb = new Arborist(opts)
await arb.prune(opts)
await reifyFinish(this.npm, arb)
}
}

View File

@ -2,6 +2,7 @@ const log = require('npmlog')
const fs = require('fs')
const parseJSON = require('json-parse-even-better-errors')
const rpj = require('read-package-json-fast')
const { resolve } = require('path')
const BaseCommand = require('./base-command.js')
class SetScript extends BaseCommand {
@ -20,6 +21,16 @@ class SetScript extends BaseCommand {
return ['[<script>] [<command>]']
}
async completion (opts) {
const argv = opts.conf.argv.remain
if (argv.length === 2) {
// find the script name
const json = resolve(this.npm.localPrefix, 'package.json')
const { scripts = {} } = await rpj(json).catch(er => ({}))
return Object.keys(scripts)
}
}
exec (args, cb) {
this.set(args).then(() => cb()).catch(cb)
}

View File

@ -38,8 +38,9 @@ class Uninstall extends BaseCommand {
async uninstall (args) {
// the /path/to/node_modules/..
const global = this.npm.config.get('global')
const prefix = this.npm.config.get('prefix')
const path = global ? resolve(this.npm.globalDir, '..') : prefix
const path = global
? resolve(this.npm.globalDir, '..')
: this.npm.localPrefix
if (!args.length) {
if (!global)
@ -60,12 +61,15 @@ class Uninstall extends BaseCommand {
}
}
const arb = new Arborist({ ...this.npm.flatOptions, path })
await arb.reify({
const opts = {
...this.npm.flatOptions,
path,
log: this.npm.log,
rm: args,
})
}
const arb = new Arborist(opts)
await arb.reify(opts)
await reifyFinish(this.npm, arb)
}
}

View File

@ -51,6 +51,7 @@ class Update extends BaseCommand {
const arb = new Arborist({
...this.npm.flatOptions,
log: this.npm.log,
path: where,
})

View File

@ -22,6 +22,36 @@ const maybeReadFile = file => {
}
}
const buildOmitList = obj => {
const include = obj.include || []
const omit = obj.omit || []
const only = obj.only
if (/^prod(uction)?$/.test(only) || obj.production)
omit.push('dev')
else if (obj.production === false)
include.push('dev')
if (/^dev/.test(obj.also))
include.push('dev')
if (obj.dev)
include.push('dev')
if (obj.optional === false)
omit.push('optional')
else if (obj.optional === true)
include.push('optional')
obj.omit = [...new Set(omit)].filter(type => !include.includes(type))
obj.include = [...new Set(include)]
if (obj.omit.includes('dev'))
process.env.NODE_ENV = 'production'
return obj.omit
}
const editor = process.env.EDITOR ||
process.env.VISUAL ||
(isWindows ? 'notepad.exe' : 'vi')
@ -115,6 +145,7 @@ define('_auth', {
is safer to use a registry-provided authentication bearer token stored in
the ~/.npmrc file by running \`npm login\`.
`,
flatten,
})
define('access', {
@ -164,12 +195,6 @@ define('also', {
`,
deprecated: 'Please use --include=dev instead.',
flatten (key, obj, flatOptions) {
if (!/^dev(elopment)?$/.test(obj.also))
return
// add to include, and call the omit flattener
obj.include = obj.include || []
obj.include.push('dev')
definitions.omit.flatten('omit', obj, flatOptions)
},
})
@ -198,7 +223,7 @@ define('audit', {
define('audit-level', {
default: null,
type: ['low', 'moderate', 'high', 'critical', 'none', null],
type: ['info', 'low', 'moderate', 'high', 'critical', 'none', null],
description: `
The minimum level of vulnerability for \`npm audit\` to exit with
a non-zero exit code.
@ -477,6 +502,18 @@ define('description', {
},
})
define('dev', {
default: false,
type: Boolean,
description: `
Alias for \`--include=dev\`.
`,
deprecated: 'Please use --include=dev instead.',
flatten (key, obj, flatOptions) {
definitions.omit.flatten('omit', obj, flatOptions)
},
})
define('diff', {
default: [],
type: [String, Array],
@ -1218,10 +1255,7 @@ define('omit', {
scripts.
`,
flatten (key, obj, flatOptions) {
const include = obj.include || []
const omit = flatOptions.omit || []
flatOptions.omit = omit.concat(obj[key])
.filter(type => type && !include.includes(type))
flatOptions.omit = buildOmitList(obj)
},
})
@ -1236,12 +1270,6 @@ define('only', {
\`--omit=dev\`.
`,
flatten (key, obj, flatOptions) {
const value = obj[key]
if (!/^prod(uction)?$/.test(value))
return
obj.omit = obj.omit || []
obj.omit.push('dev')
definitions.omit.flatten('omit', obj, flatOptions)
},
})
@ -1259,16 +1287,6 @@ define('optional', {
Alias for --include=optional or --omit=optional
`,
flatten (key, obj, flatOptions) {
const value = obj[key]
if (value === null)
return
else if (value === true) {
obj.include = obj.include || []
obj.include.push('optional')
} else {
obj.omit = obj.omit || []
obj.omit.push('optional')
}
definitions.omit.flatten('omit', obj, flatOptions)
},
})
@ -1380,17 +1398,11 @@ define('preid', {
})
define('production', {
default: false,
type: Boolean,
default: null,
type: [null, Boolean],
deprecated: 'Use `--omit=dev` instead.',
description: 'Alias for `--omit=dev`',
flatten (key, obj, flatOptions) {
const value = obj[key]
if (!value)
return
obj.omit = obj.omit || []
obj.omit.push('dev')
definitions.omit.flatten('omit', obj, flatOptions)
},
})
@ -1581,7 +1593,9 @@ define('save-prefix', {
\`npm config set save-prefix='~'\` it would be set to \`~1.2.3\` which
only allows patch upgrades.
`,
flatten,
flatten (key, obj, flatOptions) {
flatOptions.savePrefix = obj['save-exact'] ? '' : obj['save-prefix']
},
})
define('save-prod', {

View File

@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show:
.P
.RS 2
.nf
npm@7\.7\.0 /path/to/npm
npm@7\.7\.4 /path/to/npm
└─┬ init\-package\-json@0\.0\.4
└── promzard@0\.1\.5
.fi

View File

@ -10,7 +10,7 @@ npm <command> [args]
.RE
.SS Version
.P
7\.7\.0
7\.7\.4
.SS Description
.P
npm is the package manager for the Node JavaScript platform\. It puts

View File

@ -245,7 +245,7 @@ npm help \fBaudit\fP for details on what is submitted\.
.IP \(bu 2
Default: null
.IP \(bu 2
Type: "low", "moderate", "high", "critical", "none", or null
Type: "info", "low", "moderate", "high", "critical", "none", or null
.RE
.P
@ -1847,6 +1847,18 @@ DEPRECATED: This option has been deprecated in favor of \fB\-\-prefer\-offline\f
.RE
.P
\fB\-\-cache\-min=9999 (or bigger)\fP is an alias for \fB\-\-prefer\-offline\fP\|\.
.SS \fBdev\fP
.RS 0
.IP \(bu 2
Default: false
.IP \(bu 2
Type: Boolean
.IP \(bu 2
DEPRECATED: Please use \-\-include=dev instead\.
.RE
.P
Alias for \fB\-\-include=dev\fP\|\.
.SS \fBinit\.author\.email\fP
.RS 0
.IP \(bu 2
@ -1949,9 +1961,9 @@ Alias for \-\-include=optional or \-\-omit=optional
.SS \fBproduction\fP
.RS 0
.IP \(bu 2
Default: false
Default: null
.IP \(bu 2
Type: Boolean
Type: null or Boolean
.IP \(bu 2
DEPRECATED: Use \fB\-\-omit=dev\fP instead\.

View File

@ -3,3 +3,4 @@
## 1.0.0
- Initial release

View File

@ -46,3 +46,4 @@ A **String** including the appropriate [ANSI escape codes](https://en.wikipedia.
## LICENSE
[ISC](./LICENSE)

View File

@ -4,14 +4,18 @@ const isFullwidthCodePoint = require('is-fullwidth-code-point');
const emojiRegex = require('emoji-regex');
const stringWidth = string => {
string = string.replace(emojiRegex(), ' ');
if (typeof string !== 'string' || string.length === 0) {
return 0;
}
string = stripAnsi(string);
if (string.length === 0) {
return 0;
}
string = string.replace(emojiRegex(), ' ');
let width = 0;
for (let i = 0; i < string.length; i++) {

View File

@ -1,6 +1,6 @@
{
"name": "string-width",
"version": "4.2.0",
"version": "4.2.2",
"description": "Get the visual width of a string - the number of columns required to display it",
"license": "MIT",
"repository": "sindresorhus/string-width",

View File

@ -1,4 +1,4 @@
# string-width [![Build Status](https://travis-ci.org/sindresorhus/string-width.svg?branch=master)](https://travis-ci.org/sindresorhus/string-width)
# string-width
> Get the visual width of a string - the number of columns required to display it

View File

@ -13,26 +13,56 @@ declare namespace envPaths {
export interface Paths {
/**
Directory for data files.
Example locations (with the default `nodejs` suffix):
- macOS: `~/Library/Application Support/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Data` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Data`)
- Linux: `~/.local/share/MyApp-nodejs` (or `$XDG_DATA_HOME/MyApp-nodejs`)
*/
readonly data: string;
/**
Directory for data files.
Example locations (with the default `nodejs` suffix):
- macOS: `~/Library/Preferences/MyApp-nodejs`
- Windows: `%APPDATA%\MyApp-nodejs\Config` (for example, `C:\Users\USERNAME\AppData\Roaming\MyApp-nodejs\Config`)
- Linux: `~/.config/MyApp-nodejs` (or `$XDG_CONFIG_HOME/MyApp-nodejs`)
*/
readonly config: string;
/**
Directory for non-essential data files.
Example locations (with the default `nodejs` suffix):
- macOS: `~/Library/Caches/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Cache` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Cache`)
- Linux: `~/.cache/MyApp-nodejs` (or `$XDG_CACHE_HOME/MyApp-nodejs`)
*/
readonly cache: string;
/**
Directory for log files.
Example locations (with the default `nodejs` suffix):
- macOS: `~/Library/Logs/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Log` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Log`)
- Linux: `~/.local/state/MyApp-nodejs` (or `$XDG_STATE_HOME/MyApp-nodejs`)
*/
readonly log: string;
/**
Directory for temporary files.
Example locations (with the default `nodejs` suffix):
- macOS: `/var/folders/jf/f2twvvvs5jl_m49tf034ffpw0000gn/T/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\Temp\MyApp-nodejs` (for example, `C:\Users\USERNAME\AppData\Local\Temp\MyApp-nodejs`)
- Linux: `/tmp/USERNAME/MyApp-nodejs`
*/
readonly temp: string;
}
@ -42,6 +72,8 @@ declare const envPaths: {
/**
Get paths for storing things like data, config, cache, etc.
Note: It only generates the path strings. It doesn't create the directories for you. You could use [`make-dir`](https://github.com/sindresorhus/make-dir) to create the directories.
@param name - Name of your project. Used to generate the paths.
@returns The paths to use for your project on current OS.

View File

@ -1,6 +1,6 @@
{
"name": "env-paths",
"version": "2.2.0",
"version": "2.2.1",
"description": "Get paths for storing things like data, config, cache, etc",
"license": "MIT",
"repository": "sindresorhus/env-paths",

View File

@ -1,4 +1,4 @@
# env-paths [![Build Status](https://travis-ci.org/sindresorhus/env-paths.svg?branch=master)](https://travis-ci.org/sindresorhus/env-paths)
# env-paths
> Get paths for storing things like data, config, cache, etc
@ -29,7 +29,9 @@ paths.config
## API
### paths = envPaths(name, [options])
### paths = envPaths(name, options?)
Note: It only generates the path strings. It doesn't create the directories for you. You could use [`make-dir`](https://github.com/sindresorhus/make-dir) to create the directories.
#### name
@ -39,7 +41,7 @@ Name of your project. Used to generate the paths.
#### options
Type: `Object`
Type: `object`
##### suffix
@ -54,23 +56,60 @@ apps. Pass an empty string to disable it.
Directory for data files.
Example locations (with the default `nodejs` [suffix](#suffix)):
- macOS: `~/Library/Application Support/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Data` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Data`)
- Linux: `~/.local/share/MyApp-nodejs` (or `$XDG_DATA_HOME/MyApp-nodejs`)
### paths.config
Directory for config files.
Example locations (with the default `nodejs` [suffix](#suffix)):
- macOS: `~/Library/Preferences/MyApp-nodejs`
- Windows: `%APPDATA%\MyApp-nodejs\Config` (for example, `C:\Users\USERNAME\AppData\Roaming\MyApp-nodejs\Config`)
- Linux: `~/.config/MyApp-nodejs` (or `$XDG_CONFIG_HOME/MyApp-nodejs`)
### paths.cache
Directory for non-essential data files.
Example locations (with the default `nodejs` [suffix](#suffix)):
- macOS: `~/Library/Caches/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Cache` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Cache`)
- Linux: `~/.cache/MyApp-nodejs` (or `$XDG_CACHE_HOME/MyApp-nodejs`)
### paths.log
Directory for log files.
Example locations (with the default `nodejs` [suffix](#suffix)):
- macOS: `~/Library/Logs/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\MyApp-nodejs\Log` (for example, `C:\Users\USERNAME\AppData\Local\MyApp-nodejs\Log`)
- Linux: `~/.local/state/MyApp-nodejs` (or `$XDG_STATE_HOME/MyApp-nodejs`)
### paths.temp
Directory for temporary files.
Example locations (with the default `nodejs` [suffix](#suffix)):
## License
- macOS: `/var/folders/jf/f2twvvvs5jl_m49tf034ffpw0000gn/T/MyApp-nodejs`
- Windows: `%LOCALAPPDATA%\Temp\MyApp-nodejs` (for example, `C:\Users\USERNAME\AppData\Local\Temp\MyApp-nodejs`)
- Linux: `/tmp/USERNAME/MyApp-nodejs`
MIT © [Sindre Sorhus](https://sindresorhus.com)
---
<div align="center">
<b>
<a href="https://tidelift.com/subscription/pkg/npm-env-paths?utm_source=npm-env-paths&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>

View File

@ -79,7 +79,7 @@ gitHosts.gitlab = Object.assign({}, defaults, {
tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish) || 'master'}`,
extract: (url) => {
const path = url.pathname.slice(1)
if (path.includes('/-/')) {
if (path.includes('/-/') || path.includes('/archive.tar.gz')) {
return
}

View File

@ -1,6 +1,6 @@
{
"name": "hosted-git-info",
"version": "4.0.1",
"version": "4.0.2",
"description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab",
"main": "index.js",
"repository": {

View File

@ -27,3 +27,4 @@
## 1.0.0
- Initial release

View File

@ -95,3 +95,4 @@ Throws an error if either `a` or `b` are missing or if trying to diff more than
## LICENSE
[ISC](./LICENSE)

View File

@ -1,3 +1,11 @@
1.46.0 / 2021-02-13
===================
* Add extension `.amr` to `audio/amr`
* Add extension `.m4s` to `video/iso.segment`
* Add extension `.opus` to `audio/ogg`
* Add new upstream MIME types
1.45.0 / 2020-09-22
===================

View File

@ -3,7 +3,7 @@
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][travis-image]][travis-url]
[![Build Status][ci-image]][ci-url]
[![Coverage Status][coveralls-image]][coveralls-url]
This is a database of all mime types.
@ -91,6 +91,8 @@ definitively lists the media type. If an extension is going to be listed as
associateed with this media type, the source must definitively link the
media type and extension as well.
[ci-image]: https://badgen.net/github/checks/jshttp/mime-db/master?label=ci
[ci-url]: https://github.com/jshttp/mime-db/actions?query=workflow%3Aci
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-db/master
[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
[node-image]: https://badgen.net/npm/node/mime-db
@ -98,5 +100,3 @@ media type and extension as well.
[npm-downloads-image]: https://badgen.net/npm/dm/mime-db
[npm-url]: https://npmjs.org/package/mime-db
[npm-version-image]: https://badgen.net/npm/v/mime-db
[travis-image]: https://badgen.net/travis/jshttp/mime-db/master
[travis-url]: https://travis-ci.org/jshttp/mime-db

View File

@ -236,6 +236,9 @@
"application/cfw": {
"source": "iana"
},
"application/clr": {
"source": "iana"
},
"application/clue+xml": {
"source": "iana",
"compressible": true
@ -402,6 +405,15 @@
"application/efi": {
"source": "iana"
},
"application/elm+json": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/elm+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.cap+xml": {
"source": "iana",
"charset": "UTF-8",
@ -663,6 +675,10 @@
"source": "iana",
"compressible": true
},
"application/jscalendar+json": {
"source": "iana",
"compressible": true
},
"application/json": {
"source": "iana",
"charset": "UTF-8",
@ -1171,6 +1187,10 @@
"source": "iana",
"extensions": ["cww"]
},
"application/prs.cyn": {
"source": "iana",
"charset": "7-BIT"
},
"application/prs.hpub+zip": {
"source": "iana",
"compressible": false
@ -1690,6 +1710,9 @@
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.interworking-data": {
"source": "iana"
},
"application/vnd.3gpp.mc-signalling-ear": {
"source": "iana"
},
@ -1905,6 +1928,9 @@
"application/vnd.afpc.afplinedata-pagedef": {
"source": "iana"
},
"application/vnd.afpc.cmoca-cmresource": {
"source": "iana"
},
"application/vnd.afpc.foca-charset": {
"source": "iana"
},
@ -1917,6 +1943,9 @@
"application/vnd.afpc.modca": {
"source": "iana"
},
"application/vnd.afpc.modca-cmtable": {
"source": "iana"
},
"application/vnd.afpc.modca-formdef": {
"source": "iana"
},
@ -2334,6 +2363,14 @@
"application/vnd.cybank": {
"source": "iana"
},
"application/vnd.cyclonedx+json": {
"source": "iana",
"compressible": true
},
"application/vnd.cyclonedx+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.d2l.coursepackage1p0+zip": {
"source": "iana",
"compressible": false
@ -2857,6 +2894,9 @@
"source": "iana",
"extensions": ["ggb"]
},
"application/vnd.geogebra.slides": {
"source": "iana"
},
"application/vnd.geogebra.tool": {
"source": "iana",
"extensions": ["ggt"]
@ -4812,6 +4852,10 @@
"source": "iana",
"extensions": ["see"]
},
"application/vnd.seis+json": {
"source": "iana",
"compressible": true
},
"application/vnd.sema": {
"source": "iana",
"extensions": ["sema"]
@ -5232,6 +5276,9 @@
"source": "iana",
"extensions": ["wtb"]
},
"application/vnd.wfa.dpp": {
"source": "iana"
},
"application/vnd.wfa.p2p": {
"source": "iana"
},
@ -6166,7 +6213,8 @@
"extensions": ["adp"]
},
"audio/amr": {
"source": "iana"
"source": "iana",
"extensions": ["amr"]
},
"audio/amr-wb": {
"source": "iana"
@ -6415,7 +6463,7 @@
"audio/ogg": {
"source": "iana",
"compressible": false,
"extensions": ["oga","ogg","spx"]
"extensions": ["oga","ogg","spx","opus"]
},
"audio/opus": {
"source": "iana"
@ -6463,6 +6511,9 @@
"source": "apache",
"extensions": ["s3m"]
},
"audio/scip": {
"source": "iana"
},
"audio/silk": {
"source": "apache",
"extensions": ["sil"]
@ -6806,6 +6857,7 @@
"source": "iana"
},
"image/avif": {
"source": "iana",
"compressible": false,
"extensions": ["avif"]
},
@ -7463,6 +7515,15 @@
"text/coffeescript": {
"extensions": ["coffee","litcoffee"]
},
"text/cql": {
"source": "iana"
},
"text/cql-expression": {
"source": "iana"
},
"text/cql-identifier": {
"source": "iana"
},
"text/css": {
"source": "iana",
"charset": "UTF-8",
@ -7492,6 +7553,9 @@
"text/enriched": {
"source": "iana"
},
"text/fhirpath": {
"source": "iana"
},
"text/flexfec": {
"source": "iana"
},
@ -7898,6 +7962,9 @@
"source": "iana",
"extensions": ["3g2"]
},
"video/av1": {
"source": "iana"
},
"video/bmpeg": {
"source": "iana"
},
@ -7944,7 +8011,8 @@
"source": "iana"
},
"video/iso.segment": {
"source": "iana"
"source": "iana",
"extensions": ["m4s"]
},
"video/jpeg": {
"source": "iana",
@ -8024,6 +8092,9 @@
"video/rtx": {
"source": "iana"
},
"video/scip": {
"source": "iana"
},
"video/smpte291": {
"source": "iana"
},

View File

@ -1,7 +1,7 @@
{
"name": "mime-db",
"description": "Media Type Database",
"version": "1.45.0",
"version": "1.46.0",
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)",
@ -22,16 +22,16 @@
"bluebird": "3.7.2",
"co": "4.6.0",
"cogent": "1.0.1",
"csv-parse": "4.12.0",
"eslint": "7.9.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.22.0",
"csv-parse": "4.15.1",
"eslint": "7.20.0",
"eslint-config-standard": "15.0.1",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-markdown": "1.0.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "4.0.1",
"eslint-plugin-promise": "4.3.1",
"eslint-plugin-standard": "4.1.0",
"gnode": "0.1.2",
"mocha": "8.1.3",
"mocha": "8.3.0",
"nyc": "15.1.0",
"raw-body": "2.4.1",
"stream-to-array": "2.3.0"
@ -51,8 +51,8 @@
"fetch": "node scripts/fetch-apache && gnode scripts/fetch-iana && node scripts/fetch-nginx",
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test",
"test-travis": "nyc --reporter=text npm test",
"update": "npm run fetch && npm run build",
"version": "node scripts/version-history.js && git add HISTORY.md"
}

View File

@ -1,3 +1,12 @@
2.1.29 / 2021-02-17
===================
* deps: mime-db@1.46.0
- Add extension `.amr` to `audio/amr`
- Add extension `.m4s` to `video/iso.segment`
- Add extension `.opus` to `audio/ogg`
- Add new upstream MIME types
2.1.28 / 2021-01-01
===================

View File

@ -36,8 +36,6 @@ so open a PR there if you'd like to add mime types.
## API
<!-- eslint-disable no-unused-vars -->
```js
var mime = require('mime-types')
```
@ -48,8 +46,6 @@ All functions return `false` if input is invalid or not found.
Lookup the content-type associated with a file.
<!-- eslint-disable no-undef -->
```js
mime.lookup('json') // 'application/json'
mime.lookup('.md') // 'text/markdown'
@ -68,8 +64,6 @@ content-type, otherwise the given content-type is used. Then if the
content-type does not already have a `charset` parameter, `mime.charset`
is used to get the default charset and add to the returned content-type.
<!-- eslint-disable no-undef -->
```js
mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
mime.contentType('file.json') // 'application/json; charset=utf-8'
@ -84,8 +78,6 @@ mime.contentType(path.extname('/path/to/file.json')) // 'application/json; chars
Get the default extension for a content-type.
<!-- eslint-disable no-undef -->
```js
mime.extension('application/octet-stream') // 'bin'
```
@ -94,8 +86,6 @@ mime.extension('application/octet-stream') // 'bin'
Lookup the implied default charset of a content-type.
<!-- eslint-disable no-undef -->
```js
mime.charset('text/markdown') // 'UTF-8'
```

View File

@ -1,7 +1,7 @@
{
"name": "mime-types",
"description": "The ultimate javascript content-type utility.",
"version": "2.1.28",
"version": "2.1.29",
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Jeremiah Senkpiel <fishrock123@rocketmail.com> (https://searchbeam.jit.su)",
@ -14,17 +14,17 @@
],
"repository": "jshttp/mime-types",
"dependencies": {
"mime-db": "1.45.0"
"mime-db": "1.46.0"
},
"devDependencies": {
"eslint": "7.17.0",
"eslint": "7.20.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-markdown": "1.0.2",
"eslint-plugin-markdown": "2.0.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-promise": "4.3.1",
"eslint-plugin-standard": "4.1.0",
"mocha": "8.2.1",
"mocha": "8.3.0",
"nyc": "15.1.0"
},
"files": [
@ -36,7 +36,7 @@
"node": ">= 0.6"
},
"scripts": {
"lint": "eslint --plugin markdown --ext js,md .",
"lint": "eslint .",
"test": "mocha --reporter spec test/test.js",
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test"

View File

@ -1,185 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="3.0.8"></a>
## [3.0.8](https://github.com/npm/hosted-git-info/compare/v3.0.7...v3.0.8) (2021-01-28)
### Bug Fixes
* simplify the regular expression for shortcut matching ([bede0dc](https://github.com/npm/hosted-git-info/commit/bede0dc)), closes [#76](https://github.com/npm/hosted-git-info/issues/76)
<a name="3.0.7"></a>
## [3.0.7](https://github.com/npm/hosted-git-info/compare/v3.0.6...v3.0.7) (2020-10-15)
### Bug Fixes
* correctly filter out urls for tarballs in gitlab ([eb5bd5a](https://github.com/npm/hosted-git-info/commit/eb5bd5a)), closes [#69](https://github.com/npm/hosted-git-info/issues/69)
<a name="3.0.6"></a>
## [3.0.6](https://github.com/npm/hosted-git-info/compare/v3.0.5...v3.0.6) (2020-10-12)
### Bug Fixes
* support to github gist legacy hash length ([c067102](https://github.com/npm/hosted-git-info/commit/c067102)), closes [#68](https://github.com/npm/hosted-git-info/issues/68)
<a name="3.0.5"></a>
## [3.0.5](https://github.com/npm/hosted-git-info/compare/v3.0.4...v3.0.5) (2020-07-11)
<a name="3.0.4"></a>
## [3.0.4](https://github.com/npm/hosted-git-info/compare/v3.0.3...v3.0.4) (2020-02-26)
### Bug Fixes
* Do not pass scp-style URLs to the WhatWG url.URL ([0835306](https://github.com/npm/hosted-git-info/commit/0835306)), closes [#60](https://github.com/npm/hosted-git-info/issues/60) [#63](https://github.com/npm/hosted-git-info/issues/63)
<a name="3.0.3"></a>
## [3.0.3](https://github.com/npm/hosted-git-info/compare/v3.0.2...v3.0.3) (2020-02-25)
<a name="3.0.2"></a>
## [3.0.2](https://github.com/npm/hosted-git-info/compare/v3.0.1...v3.0.2) (2019-10-08)
### Bug Fixes
* do not encodeURIComponent the domain ([3e5fbec](https://github.com/npm/hosted-git-info/commit/3e5fbec)), closes [#53](https://github.com/npm/hosted-git-info/issues/53)
<a name="3.0.1"></a>
## [3.0.1](https://github.com/npm/hosted-git-info/compare/v3.0.0...v3.0.1) (2019-10-07)
### Bug Fixes
* update pathmatch for gitlab ([e3e3054](https://github.com/npm/hosted-git-info/commit/e3e3054)), closes [#52](https://github.com/npm/hosted-git-info/issues/52)
* updated pathmatch for gitlab ([fa87af7](https://github.com/npm/hosted-git-info/commit/fa87af7))
<a name="3.0.0"></a>
# [3.0.0](https://github.com/npm/hosted-git-info/compare/v2.8.3...v3.0.0) (2019-08-12)
### Bug Fixes
* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([37c2891](https://github.com/npm/hosted-git-info/commit/37c2891)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)
### BREAKING CHANGES
* **cache:** Drop support for node 0.x
<a name="2.8.3"></a>
## [2.8.3](https://github.com/npm/hosted-git-info/compare/v2.8.2...v2.8.3) (2019-08-12)
<a name="2.8.2"></a>
## [2.8.2](https://github.com/npm/hosted-git-info/compare/v2.8.1...v2.8.2) (2019-08-05)
### Bug Fixes
* http protocol use sshurl by default ([3b1d629](https://github.com/npm/hosted-git-info/commit/3b1d629)), closes [#48](https://github.com/npm/hosted-git-info/issues/48)
<a name="2.8.1"></a>
## [2.8.1](https://github.com/npm/hosted-git-info/compare/v2.8.0...v2.8.1) (2019-08-05)
### Bug Fixes
* ignore noCommittish on tarball url generation ([5d4a8d7](https://github.com/npm/hosted-git-info/commit/5d4a8d7))
* use gist tarball url that works for anonymous gists ([1692435](https://github.com/npm/hosted-git-info/commit/1692435))
<a name="2.8.0"></a>
# [2.8.0](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.0) (2019-08-05)
### Bug Fixes
* Allow slashes in gitlab project section ([bbcf7b2](https://github.com/npm/hosted-git-info/commit/bbcf7b2)), closes [#46](https://github.com/npm/hosted-git-info/issues/46) [#43](https://github.com/npm/hosted-git-info/issues/43)
* **git-host:** disallow URI-encoded slash (%2F) in `path` ([3776fa5](https://github.com/npm/hosted-git-info/commit/3776fa5)), closes [#44](https://github.com/npm/hosted-git-info/issues/44)
* **gitlab:** Do not URL encode slashes in project name for GitLab https URL ([cbf04f9](https://github.com/npm/hosted-git-info/commit/cbf04f9)), closes [#47](https://github.com/npm/hosted-git-info/issues/47)
* do not allow invalid gist urls ([d5cf830](https://github.com/npm/hosted-git-info/commit/d5cf830))
* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([e518222](https://github.com/npm/hosted-git-info/commit/e518222)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)
### Features
* give these objects a name ([60abaea](https://github.com/npm/hosted-git-info/commit/60abaea))
<a name="2.7.1"></a>
## [2.7.1](https://github.com/npm/hosted-git-info/compare/v2.7.0...v2.7.1) (2018-07-07)
### Bug Fixes
* **index:** Guard against non-string types ([5bc580d](https://github.com/npm/hosted-git-info/commit/5bc580d))
* **parse:** Crash on strings that parse to having no host ([c931482](https://github.com/npm/hosted-git-info/commit/c931482)), closes [#35](https://github.com/npm/hosted-git-info/issues/35)
<a name="2.7.0"></a>
# [2.7.0](https://github.com/npm/hosted-git-info/compare/v2.6.1...v2.7.0) (2018-07-06)
### Bug Fixes
* **github tarball:** update github tarballtemplate ([6efd582](https://github.com/npm/hosted-git-info/commit/6efd582)), closes [#34](https://github.com/npm/hosted-git-info/issues/34)
* **gitlab docs:** switched to lowercase anchors for readmes ([701bcd1](https://github.com/npm/hosted-git-info/commit/701bcd1))
### Features
* **all:** Support www. prefixes on hostnames ([3349575](https://github.com/npm/hosted-git-info/commit/3349575)), closes [#32](https://github.com/npm/hosted-git-info/issues/32)
<a name="2.6.1"></a>
## [2.6.1](https://github.com/npm/hosted-git-info/compare/v2.6.0...v2.6.1) (2018-06-25)
### Bug Fixes
* **Revert:** "compat: remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25))" ([cce5a62](https://github.com/npm/hosted-git-info/commit/cce5a62))
* **Revert:** "git-host: fix forgotten extend()" ([a815ec9](https://github.com/npm/hosted-git-info/commit/a815ec9))
<a name="2.6.0"></a>
# [2.6.0](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.6.0) (2018-03-07)
### Bug Fixes
* **compat:** remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25)) ([627ab55](https://github.com/npm/hosted-git-info/commit/627ab55))
* **git-host:** fix forgotten extend() ([eba1f7b](https://github.com/npm/hosted-git-info/commit/eba1f7b))
### Features
* **browse:** fragment support for browse() ([#28](https://github.com/npm/hosted-git-info/issues/28)) ([cd5e5bb](https://github.com/npm/hosted-git-info/commit/cd5e5bb))

View File

@ -1,13 +0,0 @@
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

@ -1,133 +0,0 @@
# 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
var hostedGitInfo = require("hosted-git-info")
var 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
### var 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
`master` 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, Bitbucket and GitLab. Pull requests for
additional hosts welcome.

View File

@ -1,154 +0,0 @@
'use strict'
const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : ''
const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : ''
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)}`,
browsetemplate: ({ domain, user, project, committish, treepath }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`,
browsefiletemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'master')}/${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) || 'master'}/${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 gitHosts = {}
gitHosts.github = Object.assign({}, defaults, {
// 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',
filetemplate: ({ auth, user, project, committish, path }) => `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish) || 'master'}/${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) || 'master'}`,
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 }
}
})
gitHosts.bitbucket = Object.assign({}, defaults, {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'bitbucket.org',
treepath: 'src',
tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/get/${maybeEncode(committish) || 'master'}.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) }
}
})
gitHosts.gitlab = Object.assign({}, defaults, {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gitlab.com',
treepath: 'tree',
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) || 'master'}`,
extract: (url) => {
const path = url.pathname.slice(1)
if (path.includes('/-/')) {
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) }
}
})
gitHosts.gist = Object.assign({}, defaults, {
protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gist.github.com',
sshtemplate: ({ domain, project, committish }) => `git@${domain}:${project}.git${maybeJoin('#', committish)}`,
sshurltemplate: ({ domain, project, committish }) => `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`,
browsetemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
browsefiletemplate: ({ 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) || 'master'}`,
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)
}
})
const names = Object.keys(gitHosts)
gitHosts.byShortcut = {}
gitHosts.byDomain = {}
for (const name of names) {
gitHosts.byShortcut[`${name}:`] = name
gitHosts.byDomain[gitHosts[name].domain] = name
}
function formatHashFragment (fragment) {
return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
}
module.exports = gitHosts

View File

@ -1,110 +0,0 @@
'use strict'
const gitHosts = require('./git-host-info.js')
class GitHost {
constructor (type, user, auth, project, committish, defaultRepresentation, opts = {}) {
Object.assign(this, gitHosts[type])
this.type = type
this.user = user
this.auth = auth
this.project = project
this.committish = committish
this.default = defaultRepresentation
this.opts = opts
}
hash () {
return this.committish ? `#${this.committish}` : ''
}
ssh (opts) {
return this._fill(this.sshtemplate, opts)
}
_fill (template, opts) {
if (typeof template === 'function') {
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
}
return null
}
sshurl (opts) {
return this._fill(this.sshurltemplate, opts)
}
browse (path, fragment, opts) {
// not a string, treat path as opts
if (typeof path !== 'string') {
return this._fill(this.browsetemplate, path)
}
if (typeof fragment !== 'string') {
opts = fragment
fragment = null
}
return this._fill(this.browsefiletemplate, { ...opts, fragment, 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 })
}
getDefaultRepresentation () {
return this.default
}
toString (opts) {
if (this.default && typeof this[this.default] === 'function') {
return this[this.default](opts)
}
return this.sshurl(opts)
}
}
module.exports = GitHost

View File

@ -1,237 +0,0 @@
'use strict'
const url = require('url')
const gitHosts = require('./git-host-info.js')
const GitHost = module.exports = require('./git-host.js')
const LRU = require('lru-cache')
const cache = new LRU({ max: 1000 })
const protocolToRepresentationMap = {
'git+ssh:': 'sshurl',
'git+https:': 'https',
'ssh:': 'sshurl',
'git:': 'git'
}
function protocolToRepresentation (protocol) {
return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
}
const authProtocols = {
'git:': true,
'https:': true,
'git+https:': true,
'http:': true,
'git+http:': true
}
const knownProtocols = Object.keys(gitHosts.byShortcut).concat(['http:', 'https:', 'git:', 'git+ssh:', 'git+https:', 'ssh:'])
module.exports.fromUrl = function (giturl, opts) {
if (typeof giturl !== 'string') {
return
}
const key = giturl + JSON.stringify(opts || {})
if (!cache.has(key)) {
cache.set(key, fromUrl(giturl, opts))
}
return cache.get(key)
}
function fromUrl (giturl, opts) {
if (!giturl) {
return
}
const url = isGitHubShorthand(giturl) ? 'github:' + giturl : correctProtocol(giturl)
const parsed = parseGitUrl(url)
if (!parsed) {
return parsed
}
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 (authProtocols[parsed.protocol] && (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 = protocolToRepresentation(parsed.protocol)
}
} catch (err) {
/* istanbul ignore else */
if (err instanceof URIError) {
return
} else {
throw err
}
}
return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
}
// accepts input like git:github.com:user/repo and inserts the // after the first :
const correctProtocol = (arg) => {
const firstColon = arg.indexOf(':')
const proto = arg.slice(0, firstColon + 1)
if (knownProtocols.includes(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)
}
// 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
}
// attempt to correct an scp style url so that it will parse with `new URL()`
const correctUrl = (giturl) => {
const firstAt = giturl.indexOf('@')
const lastHash = giturl.lastIndexOf('#')
let firstColon = giturl.indexOf(':')
let lastColon = giturl.lastIndexOf(':', lastHash > -1 ? lastHash : Infinity)
let corrected
if (lastColon > 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
corrected = giturl.slice(0, lastColon) + '/' + giturl.slice(lastColon + 1)
// // and we find our new : positions
firstColon = corrected.indexOf(':')
lastColon = corrected.lastIndexOf(':')
}
if (firstColon === -1 && giturl.indexOf('//') === -1) {
// we have no : at all
// as it would be in:
// username@hostname.com/user/repo
// then we prepend a protocol
corrected = `git+ssh://${corrected}`
}
return corrected
}
// try to parse the url as its given to us, if that throws
// then we try to clean the url and parse that result instead
// THIS FUNCTION SHOULD NEVER THROW
const parseGitUrl = (giturl) => {
let result
try {
result = new url.URL(giturl)
} catch (err) {}
if (result) {
return result
}
const correctedUrl = correctUrl(giturl)
try {
result = new url.URL(correctedUrl)
} catch (err) {}
return result
}

View File

@ -1,52 +0,0 @@
{
"name": "hosted-git-info",
"version": "4.0.1",
"description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/npm/hosted-git-info.git"
},
"keywords": [
"git",
"github",
"bitbucket",
"gitlab"
],
"author": "Rebecca Turner <me@re-becca.org> (http://re-becca.org)",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/hosted-git-info/issues"
},
"homepage": "https://github.com/npm/hosted-git-info",
"scripts": {
"posttest": "standard",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"preversion": "npm test",
"snap": "tap",
"test": "tap",
"test:coverage": "tap --coverage-report=html"
},
"dependencies": {
"lru-cache": "^6.0.0"
},
"devDependencies": {
"standard": "^16.0.3",
"standard-version": "^9.1.0",
"tap": "^14.11.0"
},
"files": [
"index.js",
"git-host.js",
"git-host-info.js"
],
"engines": {
"node": ">=10"
},
"tap": {
"color": 1,
"coverage": true,
"esm": false
}
}

View File

@ -1,185 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="3.0.8"></a>
## [3.0.8](https://github.com/npm/hosted-git-info/compare/v3.0.7...v3.0.8) (2021-01-28)
### Bug Fixes
* simplify the regular expression for shortcut matching ([bede0dc](https://github.com/npm/hosted-git-info/commit/bede0dc)), closes [#76](https://github.com/npm/hosted-git-info/issues/76)
<a name="3.0.7"></a>
## [3.0.7](https://github.com/npm/hosted-git-info/compare/v3.0.6...v3.0.7) (2020-10-15)
### Bug Fixes
* correctly filter out urls for tarballs in gitlab ([eb5bd5a](https://github.com/npm/hosted-git-info/commit/eb5bd5a)), closes [#69](https://github.com/npm/hosted-git-info/issues/69)
<a name="3.0.6"></a>
## [3.0.6](https://github.com/npm/hosted-git-info/compare/v3.0.5...v3.0.6) (2020-10-12)
### Bug Fixes
* support to github gist legacy hash length ([c067102](https://github.com/npm/hosted-git-info/commit/c067102)), closes [#68](https://github.com/npm/hosted-git-info/issues/68)
<a name="3.0.5"></a>
## [3.0.5](https://github.com/npm/hosted-git-info/compare/v3.0.4...v3.0.5) (2020-07-11)
<a name="3.0.4"></a>
## [3.0.4](https://github.com/npm/hosted-git-info/compare/v3.0.3...v3.0.4) (2020-02-26)
### Bug Fixes
* Do not pass scp-style URLs to the WhatWG url.URL ([0835306](https://github.com/npm/hosted-git-info/commit/0835306)), closes [#60](https://github.com/npm/hosted-git-info/issues/60) [#63](https://github.com/npm/hosted-git-info/issues/63)
<a name="3.0.3"></a>
## [3.0.3](https://github.com/npm/hosted-git-info/compare/v3.0.2...v3.0.3) (2020-02-25)
<a name="3.0.2"></a>
## [3.0.2](https://github.com/npm/hosted-git-info/compare/v3.0.1...v3.0.2) (2019-10-08)
### Bug Fixes
* do not encodeURIComponent the domain ([3e5fbec](https://github.com/npm/hosted-git-info/commit/3e5fbec)), closes [#53](https://github.com/npm/hosted-git-info/issues/53)
<a name="3.0.1"></a>
## [3.0.1](https://github.com/npm/hosted-git-info/compare/v3.0.0...v3.0.1) (2019-10-07)
### Bug Fixes
* update pathmatch for gitlab ([e3e3054](https://github.com/npm/hosted-git-info/commit/e3e3054)), closes [#52](https://github.com/npm/hosted-git-info/issues/52)
* updated pathmatch for gitlab ([fa87af7](https://github.com/npm/hosted-git-info/commit/fa87af7))
<a name="3.0.0"></a>
# [3.0.0](https://github.com/npm/hosted-git-info/compare/v2.8.3...v3.0.0) (2019-08-12)
### Bug Fixes
* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([37c2891](https://github.com/npm/hosted-git-info/commit/37c2891)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)
### BREAKING CHANGES
* **cache:** Drop support for node 0.x
<a name="2.8.3"></a>
## [2.8.3](https://github.com/npm/hosted-git-info/compare/v2.8.2...v2.8.3) (2019-08-12)
<a name="2.8.2"></a>
## [2.8.2](https://github.com/npm/hosted-git-info/compare/v2.8.1...v2.8.2) (2019-08-05)
### Bug Fixes
* http protocol use sshurl by default ([3b1d629](https://github.com/npm/hosted-git-info/commit/3b1d629)), closes [#48](https://github.com/npm/hosted-git-info/issues/48)
<a name="2.8.1"></a>
## [2.8.1](https://github.com/npm/hosted-git-info/compare/v2.8.0...v2.8.1) (2019-08-05)
### Bug Fixes
* ignore noCommittish on tarball url generation ([5d4a8d7](https://github.com/npm/hosted-git-info/commit/5d4a8d7))
* use gist tarball url that works for anonymous gists ([1692435](https://github.com/npm/hosted-git-info/commit/1692435))
<a name="2.8.0"></a>
# [2.8.0](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.0) (2019-08-05)
### Bug Fixes
* Allow slashes in gitlab project section ([bbcf7b2](https://github.com/npm/hosted-git-info/commit/bbcf7b2)), closes [#46](https://github.com/npm/hosted-git-info/issues/46) [#43](https://github.com/npm/hosted-git-info/issues/43)
* **git-host:** disallow URI-encoded slash (%2F) in `path` ([3776fa5](https://github.com/npm/hosted-git-info/commit/3776fa5)), closes [#44](https://github.com/npm/hosted-git-info/issues/44)
* **gitlab:** Do not URL encode slashes in project name for GitLab https URL ([cbf04f9](https://github.com/npm/hosted-git-info/commit/cbf04f9)), closes [#47](https://github.com/npm/hosted-git-info/issues/47)
* do not allow invalid gist urls ([d5cf830](https://github.com/npm/hosted-git-info/commit/d5cf830))
* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([e518222](https://github.com/npm/hosted-git-info/commit/e518222)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)
### Features
* give these objects a name ([60abaea](https://github.com/npm/hosted-git-info/commit/60abaea))
<a name="2.7.1"></a>
## [2.7.1](https://github.com/npm/hosted-git-info/compare/v2.7.0...v2.7.1) (2018-07-07)
### Bug Fixes
* **index:** Guard against non-string types ([5bc580d](https://github.com/npm/hosted-git-info/commit/5bc580d))
* **parse:** Crash on strings that parse to having no host ([c931482](https://github.com/npm/hosted-git-info/commit/c931482)), closes [#35](https://github.com/npm/hosted-git-info/issues/35)
<a name="2.7.0"></a>
# [2.7.0](https://github.com/npm/hosted-git-info/compare/v2.6.1...v2.7.0) (2018-07-06)
### Bug Fixes
* **github tarball:** update github tarballtemplate ([6efd582](https://github.com/npm/hosted-git-info/commit/6efd582)), closes [#34](https://github.com/npm/hosted-git-info/issues/34)
* **gitlab docs:** switched to lowercase anchors for readmes ([701bcd1](https://github.com/npm/hosted-git-info/commit/701bcd1))
### Features
* **all:** Support www. prefixes on hostnames ([3349575](https://github.com/npm/hosted-git-info/commit/3349575)), closes [#32](https://github.com/npm/hosted-git-info/issues/32)
<a name="2.6.1"></a>
## [2.6.1](https://github.com/npm/hosted-git-info/compare/v2.6.0...v2.6.1) (2018-06-25)
### Bug Fixes
* **Revert:** "compat: remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25))" ([cce5a62](https://github.com/npm/hosted-git-info/commit/cce5a62))
* **Revert:** "git-host: fix forgotten extend()" ([a815ec9](https://github.com/npm/hosted-git-info/commit/a815ec9))
<a name="2.6.0"></a>
# [2.6.0](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.6.0) (2018-03-07)
### Bug Fixes
* **compat:** remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25)) ([627ab55](https://github.com/npm/hosted-git-info/commit/627ab55))
* **git-host:** fix forgotten extend() ([eba1f7b](https://github.com/npm/hosted-git-info/commit/eba1f7b))
### Features
* **browse:** fragment support for browse() ([#28](https://github.com/npm/hosted-git-info/issues/28)) ([cd5e5bb](https://github.com/npm/hosted-git-info/commit/cd5e5bb))

View File

@ -1,13 +0,0 @@
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

@ -1,133 +0,0 @@
# 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
var hostedGitInfo = require("hosted-git-info")
var 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
### var 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
`master` 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, Bitbucket and GitLab. Pull requests for
additional hosts welcome.

View File

@ -1,154 +0,0 @@
'use strict'
const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : ''
const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : ''
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)}`,
browsetemplate: ({ domain, user, project, committish, treepath }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`,
browsefiletemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'master')}/${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) || 'master'}/${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 gitHosts = {}
gitHosts.github = Object.assign({}, defaults, {
// 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',
filetemplate: ({ auth, user, project, committish, path }) => `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish) || 'master'}/${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) || 'master'}`,
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 }
}
})
gitHosts.bitbucket = Object.assign({}, defaults, {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'bitbucket.org',
treepath: 'src',
tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/get/${maybeEncode(committish) || 'master'}.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) }
}
})
gitHosts.gitlab = Object.assign({}, defaults, {
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gitlab.com',
treepath: 'tree',
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) || 'master'}`,
extract: (url) => {
const path = url.pathname.slice(1)
if (path.includes('/-/')) {
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) }
}
})
gitHosts.gist = Object.assign({}, defaults, {
protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
domain: 'gist.github.com',
sshtemplate: ({ domain, project, committish }) => `git@${domain}:${project}.git${maybeJoin('#', committish)}`,
sshurltemplate: ({ domain, project, committish }) => `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`,
browsetemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
browsefiletemplate: ({ 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) || 'master'}`,
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)
}
})
const names = Object.keys(gitHosts)
gitHosts.byShortcut = {}
gitHosts.byDomain = {}
for (const name of names) {
gitHosts.byShortcut[`${name}:`] = name
gitHosts.byDomain[gitHosts[name].domain] = name
}
function formatHashFragment (fragment) {
return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
}
module.exports = gitHosts

View File

@ -1,110 +0,0 @@
'use strict'
const gitHosts = require('./git-host-info.js')
class GitHost {
constructor (type, user, auth, project, committish, defaultRepresentation, opts = {}) {
Object.assign(this, gitHosts[type])
this.type = type
this.user = user
this.auth = auth
this.project = project
this.committish = committish
this.default = defaultRepresentation
this.opts = opts
}
hash () {
return this.committish ? `#${this.committish}` : ''
}
ssh (opts) {
return this._fill(this.sshtemplate, opts)
}
_fill (template, opts) {
if (typeof template === 'function') {
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
}
return null
}
sshurl (opts) {
return this._fill(this.sshurltemplate, opts)
}
browse (path, fragment, opts) {
// not a string, treat path as opts
if (typeof path !== 'string') {
return this._fill(this.browsetemplate, path)
}
if (typeof fragment !== 'string') {
opts = fragment
fragment = null
}
return this._fill(this.browsefiletemplate, { ...opts, fragment, 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 })
}
getDefaultRepresentation () {
return this.default
}
toString (opts) {
if (this.default && typeof this[this.default] === 'function') {
return this[this.default](opts)
}
return this.sshurl(opts)
}
}
module.exports = GitHost

View File

@ -1,237 +0,0 @@
'use strict'
const url = require('url')
const gitHosts = require('./git-host-info.js')
const GitHost = module.exports = require('./git-host.js')
const LRU = require('lru-cache')
const cache = new LRU({ max: 1000 })
const protocolToRepresentationMap = {
'git+ssh:': 'sshurl',
'git+https:': 'https',
'ssh:': 'sshurl',
'git:': 'git'
}
function protocolToRepresentation (protocol) {
return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
}
const authProtocols = {
'git:': true,
'https:': true,
'git+https:': true,
'http:': true,
'git+http:': true
}
const knownProtocols = Object.keys(gitHosts.byShortcut).concat(['http:', 'https:', 'git:', 'git+ssh:', 'git+https:', 'ssh:'])
module.exports.fromUrl = function (giturl, opts) {
if (typeof giturl !== 'string') {
return
}
const key = giturl + JSON.stringify(opts || {})
if (!cache.has(key)) {
cache.set(key, fromUrl(giturl, opts))
}
return cache.get(key)
}
function fromUrl (giturl, opts) {
if (!giturl) {
return
}
const url = isGitHubShorthand(giturl) ? 'github:' + giturl : correctProtocol(giturl)
const parsed = parseGitUrl(url)
if (!parsed) {
return parsed
}
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 (authProtocols[parsed.protocol] && (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 = protocolToRepresentation(parsed.protocol)
}
} catch (err) {
/* istanbul ignore else */
if (err instanceof URIError) {
return
} else {
throw err
}
}
return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
}
// accepts input like git:github.com:user/repo and inserts the // after the first :
const correctProtocol = (arg) => {
const firstColon = arg.indexOf(':')
const proto = arg.slice(0, firstColon + 1)
if (knownProtocols.includes(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)
}
// 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
}
// attempt to correct an scp style url so that it will parse with `new URL()`
const correctUrl = (giturl) => {
const firstAt = giturl.indexOf('@')
const lastHash = giturl.lastIndexOf('#')
let firstColon = giturl.indexOf(':')
let lastColon = giturl.lastIndexOf(':', lastHash > -1 ? lastHash : Infinity)
let corrected
if (lastColon > 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
corrected = giturl.slice(0, lastColon) + '/' + giturl.slice(lastColon + 1)
// // and we find our new : positions
firstColon = corrected.indexOf(':')
lastColon = corrected.lastIndexOf(':')
}
if (firstColon === -1 && giturl.indexOf('//') === -1) {
// we have no : at all
// as it would be in:
// username@hostname.com/user/repo
// then we prepend a protocol
corrected = `git+ssh://${corrected}`
}
return corrected
}
// try to parse the url as its given to us, if that throws
// then we try to clean the url and parse that result instead
// THIS FUNCTION SHOULD NEVER THROW
const parseGitUrl = (giturl) => {
let result
try {
result = new url.URL(giturl)
} catch (err) {}
if (result) {
return result
}
const correctedUrl = correctUrl(giturl)
try {
result = new url.URL(correctedUrl)
} catch (err) {}
return result
}

View File

@ -1,52 +0,0 @@
{
"name": "hosted-git-info",
"version": "4.0.1",
"description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/npm/hosted-git-info.git"
},
"keywords": [
"git",
"github",
"bitbucket",
"gitlab"
],
"author": "Rebecca Turner <me@re-becca.org> (http://re-becca.org)",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/hosted-git-info/issues"
},
"homepage": "https://github.com/npm/hosted-git-info",
"scripts": {
"posttest": "standard",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"preversion": "npm test",
"snap": "tap",
"test": "tap",
"test:coverage": "tap --coverage-report=html"
},
"dependencies": {
"lru-cache": "^6.0.0"
},
"devDependencies": {
"standard": "^16.0.3",
"standard-version": "^9.1.0",
"tap": "^14.11.0"
},
"files": [
"index.js",
"git-host.js",
"git-host-info.js"
],
"engines": {
"node": ">=10"
},
"tap": {
"color": 1,
"coverage": true,
"esm": false
}
}

View File

@ -213,3 +213,4 @@ test('readPackageSync', function (t) {
);
});
});

View File

@ -4,11 +4,12 @@ Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Inc
### Features
* Supports SOCKS v4, v4a, and v5 protocols.
* Supports SOCKS v4, v4a, v5, and v5h protocols.
* Supports the CONNECT, BIND, and ASSOCIATE commands.
* Supports callbacks, promises, and events for proxy connection creation async flow control.
* Supports proxy chaining (CONNECT only).
* Supports user/pass authentication.
* Supports user/password authentication.
* Supports custom authentication.
* Built in UDP frame creation & parse functions.
* Created with TypeScript, type definitions are provided.
@ -396,17 +397,19 @@ Looking for a guide to migrate from v1? Look [here](docs/migratingFromV1.md)
### SocksClient
SocksClient establishes SOCKS proxy connections to remote destination hosts. These proxy connections are fully transparent to the server and once established act as full duplex streams. SOCKS v4, v4a, and v5 are supported, as well as the connect, bind, and associate commands.
SocksClient establishes SOCKS proxy connections to remote destination hosts. These proxy connections are fully transparent to the server and once established act as full duplex streams. SOCKS v4, v4a, v5, and v5h are supported, as well as the connect, bind, and associate commands.
SocksClient supports creating connections using callbacks, promises, and async/await flow control using two static factory functions createConnection and createConnectionChain. It also internally extends EventEmitter which results in allowing event handling based async flow control.
**SOCKS Compatibility Table**
Note: When using 4a please specify type: 4, and when using 5h please specify type 5.
| Socks Version | TCP | UDP | IPv4 | IPv6 | Hostname |
| --- | :---: | :---: | :---: | :---: | :---: |
| SOCKS v4 | ✅ | ❌ | ✅ | ❌ | ❌ |
| SOCKS v4a | ✅ | ❌ | ✅ | ❌ | ✅ |
| SOCKS v5 | ✅ | ✅ | ✅ | ✅ | ✅ |
| SOCKS v5 (includes 5hh) | ✅ | ✅ | ✅ | ✅ | ✅ |
### new SocksClient(options)
@ -419,11 +422,22 @@ SocksClient supports creating connections using callbacks, promises, and async/a
proxy: {
host: '159.203.75.200', // ipv4, ipv6, or hostname
port: 1080,
type: 5 // Proxy version (4 or 5). For v4a, just use 4.
type: 5 // Proxy version (4 or 5). For v4a use 4, for v5h use 5.
// Optional fields
userId: 'some username', // Used for SOCKS4 userId auth, and SOCKS5 user/pass auth in conjunction with password.
password: 'some password' // Used in conjunction with userId for user/pass auth for SOCKS5 proxies.
password: 'some password', // Used in conjunction with userId for user/pass auth for SOCKS5 proxies.
custom_auth_method: 0x80, // If using a custom auth method, specify the type here. If this is set, ALL other custom_auth_*** options must be set as well.
custom_auth_request_handler: async () =>. {
// This will be called when it's time to send the custom auth handshake. You must return a Buffer containing the data to send as your authentication.
return Buffer.from([0x01,0x02,0x03]);
},
// This is the expected size (bytes) of the custom auth response from the proxy server.
custom_auth_response_size: 2,
// This is called when the auth response is received. The received packet is passed in as a Buffer, and you must return a boolean indicating the response from the server said your custom auth was successful or failed.
custom_auth_response_handler: async (data) => {
return data[1] === 0x00;
}
},
command: 'connect', // connect, bind, associate

View File

@ -45,7 +45,7 @@ class SocksClient extends events_1.EventEmitter {
catch (err) {
if (typeof callback === 'function') {
callback(err);
return resolve(); // Resolves pending promise (prevents memory leaks).
return resolve(err); // Resolves pending promise (prevents memory leaks).
}
else {
return reject(err);
@ -57,7 +57,7 @@ class SocksClient extends events_1.EventEmitter {
client.removeAllListeners();
if (typeof callback === 'function') {
callback(null, info);
resolve(); // Resolves pending promise (prevents memory leaks).
resolve(info); // Resolves pending promise (prevents memory leaks).
}
else {
resolve(info);
@ -68,7 +68,7 @@ class SocksClient extends events_1.EventEmitter {
client.removeAllListeners();
if (typeof callback === 'function') {
callback(err);
resolve(); // Resolves pending promise (prevents memory leaks).
resolve(err); // Resolves pending promise (prevents memory leaks).
}
else {
reject(err);
@ -94,7 +94,7 @@ class SocksClient extends events_1.EventEmitter {
catch (err) {
if (typeof callback === 'function') {
callback(err);
return resolve(); // Resolves pending promise (prevents memory leaks).
return resolve(err); // Resolves pending promise (prevents memory leaks).
}
else {
return reject(err);
@ -121,6 +121,7 @@ class SocksClient extends events_1.EventEmitter {
command: 'connect',
proxy: nextProxy,
destination: nextDestination,
// Initial connection ignores this as sock is undefined. Subsequent connections re-use the first proxy socket to form a chain.
});
// If sock is undefined, assign it here.
if (!sock) {
@ -129,7 +130,7 @@ class SocksClient extends events_1.EventEmitter {
}
if (typeof callback === 'function') {
callback(null, { socket: sock });
resolve(); // Resolves pending promise (prevents memory leaks).
resolve({ socket: sock }); // Resolves pending promise (prevents memory leaks).
}
else {
resolve({ socket: sock });
@ -138,7 +139,7 @@ class SocksClient extends events_1.EventEmitter {
catch (err) {
if (typeof callback === 'function') {
callback(err);
resolve(); // Resolves pending promise (prevents memory leaks).
resolve(err); // Resolves pending promise (prevents memory leaks).
}
else {
reject(err);
@ -472,17 +473,22 @@ class SocksClient extends events_1.EventEmitter {
*/
sendSocks5InitialHandshake() {
const buff = new smart_buffer_1.SmartBuffer();
buff.writeUInt8(0x05);
// By default we always support no auth.
const supportedAuthMethods = [constants_1.Socks5Auth.NoAuth];
// We should only tell the proxy we support user/pass auth if auth info is actually provided.
// Note: As of Tor v0.3.5.7+, if user/pass auth is an option from the client, by default it will always take priority.
if (this.options.proxy.userId || this.options.proxy.password) {
buff.writeUInt8(2);
buff.writeUInt8(constants_1.Socks5Auth.NoAuth);
buff.writeUInt8(constants_1.Socks5Auth.UserPass);
supportedAuthMethods.push(constants_1.Socks5Auth.UserPass);
}
else {
buff.writeUInt8(1);
buff.writeUInt8(constants_1.Socks5Auth.NoAuth);
// Custom auth method?
if (this.options.proxy.custom_auth_method !== undefined) {
supportedAuthMethods.push(this.options.proxy.custom_auth_method);
}
// Build handshake packet
buff.writeUInt8(0x05);
buff.writeUInt8(supportedAuthMethods.length);
for (const authMethod of supportedAuthMethods) {
buff.writeUInt8(authMethod);
}
this.nextRequiredPacketBufferSize =
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5InitialHandshakeResponse;
@ -498,17 +504,24 @@ class SocksClient extends events_1.EventEmitter {
if (data[0] !== 0x05) {
this.closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion);
}
else if (data[1] === 0xff) {
else if (data[1] === constants_1.SOCKS5_NO_ACCEPTABLE_AUTH) {
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeNoAcceptedAuthType);
}
else {
// If selected Socks v5 auth method is no auth, send final handshake request.
if (data[1] === constants_1.Socks5Auth.NoAuth) {
this.socks5ChosenAuthType = constants_1.Socks5Auth.NoAuth;
this.sendSocks5CommandRequest();
// If selected Socks v5 auth method is user/password, send auth handshake.
}
else if (data[1] === constants_1.Socks5Auth.UserPass) {
this.socks5ChosenAuthType = constants_1.Socks5Auth.UserPass;
this.sendSocks5UserPassAuthentication();
// If selected Socks v5 auth method is the custom_auth_method, send custom handshake.
}
else if (data[1] === this.options.proxy.custom_auth_method) {
this.socks5ChosenAuthType = this.options.proxy.custom_auth_method;
this.sendSocks5CustomAuthentication();
}
else {
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeUnknownAuthType);
@ -534,19 +547,52 @@ class SocksClient extends events_1.EventEmitter {
this.socket.write(buff.toBuffer());
this.setState(constants_1.SocksClientState.SentAuthentication);
}
sendSocks5CustomAuthentication() {
return __awaiter(this, void 0, void 0, function* () {
this.nextRequiredPacketBufferSize = this.options.proxy.custom_auth_response_size;
this.socket.write(yield this.options.proxy.custom_auth_request_handler());
this.setState(constants_1.SocksClientState.SentAuthentication);
});
}
handleSocks5CustomAuthHandshakeResponse(data) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.options.proxy.custom_auth_response_handler(data);
});
}
handleSocks5AuthenticationNoAuthHandshakeResponse(data) {
return __awaiter(this, void 0, void 0, function* () {
return data[1] === 0x00;
});
}
handleSocks5AuthenticationUserPassHandshakeResponse(data) {
return __awaiter(this, void 0, void 0, function* () {
return data[1] === 0x00;
});
}
/**
* Handles Socks v5 auth handshake response.
* @param data
*/
handleInitialSocks5AuthenticationHandshakeResponse() {
return __awaiter(this, void 0, void 0, function* () {
this.setState(constants_1.SocksClientState.ReceivedAuthenticationResponse);
const data = this.receiveBuffer.get(2);
if (data[1] !== 0x00) {
let authResult = false;
if (this.socks5ChosenAuthType === constants_1.Socks5Auth.NoAuth) {
authResult = yield this.handleSocks5AuthenticationNoAuthHandshakeResponse(this.receiveBuffer.get(2));
}
else if (this.socks5ChosenAuthType === constants_1.Socks5Auth.UserPass) {
authResult = yield this.handleSocks5AuthenticationUserPassHandshakeResponse(this.receiveBuffer.get(2));
}
else if (this.socks5ChosenAuthType === this.options.proxy.custom_auth_method) {
authResult = yield this.handleSocks5CustomAuthHandshakeResponse(this.receiveBuffer.get(this.options.proxy.custom_auth_response_size));
}
if (!authResult) {
this.closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed);
}
else {
this.sendSocks5CommandRequest();
}
});
}
/**
* Sends Socks v5 final handshake request.

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SOCKS_INCOMING_PACKET_SIZES = exports.SocksClientState = exports.Socks5Response = exports.Socks5HostType = exports.Socks5Auth = exports.Socks4Response = exports.SocksCommand = exports.ERRORS = exports.DEFAULT_TIMEOUT = void 0;
exports.SOCKS5_NO_ACCEPTABLE_AUTH = exports.SOCKS5_CUSTOM_AUTH_END = exports.SOCKS5_CUSTOM_AUTH_START = exports.SOCKS_INCOMING_PACKET_SIZES = exports.SocksClientState = exports.Socks5Response = exports.Socks5HostType = exports.Socks5Auth = exports.Socks4Response = exports.SocksCommand = exports.ERRORS = exports.DEFAULT_TIMEOUT = void 0;
const DEFAULT_TIMEOUT = 30000;
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
// prettier-ignore
@ -13,6 +13,8 @@ const ERRORS = {
InvalidSocksClientOptionsProxy: 'Invalid SOCKS proxy details were provided.',
InvalidSocksClientOptionsTimeout: 'An invalid timeout value was provided. Please enter a value above 0 (in ms).',
InvalidSocksClientOptionsProxiesLength: 'At least two socks proxies must be provided for chaining.',
InvalidSocksClientOptionsCustomAuthRange: 'Custom auth must be a value between 0x80 and 0xFE.',
InvalidSocksClientOptionsCustomAuthOptions: 'When a custom_auth_method is provided, custom_auth_request_handler, custom_auth_response_size, and custom_auth_response_handler must also be provided and valid.',
NegotiationError: 'Negotiation error',
SocketClosed: 'Socket closed',
ProxyConnectionTimedOut: 'Proxy connection timed out',
@ -41,7 +43,7 @@ const SOCKS_INCOMING_PACKET_SIZES = {
Socks5ResponseIPv6: 22,
Socks5ResponseHostname: (hostNameLength) => hostNameLength + 7,
// Command response + incoming connection (bind)
Socks4Response: 8,
Socks4Response: 8, // 2 header + 2 port + 4 ip
};
exports.SOCKS_INCOMING_PACKET_SIZES = SOCKS_INCOMING_PACKET_SIZES;
var SocksCommand;
@ -66,6 +68,12 @@ var Socks5Auth;
Socks5Auth[Socks5Auth["UserPass"] = 2] = "UserPass";
})(Socks5Auth || (Socks5Auth = {}));
exports.Socks5Auth = Socks5Auth;
const SOCKS5_CUSTOM_AUTH_START = 0x80;
exports.SOCKS5_CUSTOM_AUTH_START = SOCKS5_CUSTOM_AUTH_START;
const SOCKS5_CUSTOM_AUTH_END = 0xfe;
exports.SOCKS5_CUSTOM_AUTH_END = SOCKS5_CUSTOM_AUTH_END;
const SOCKS5_NO_ACCEPTABLE_AUTH = 0xff;
exports.SOCKS5_NO_ACCEPTABLE_AUTH = SOCKS5_NO_ACCEPTABLE_AUTH;
var Socks5Response;
(function (Socks5Response) {
Socks5Response[Socks5Response["Granted"] = 0] = "Granted";

View File

@ -1 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"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"}

View File

@ -26,6 +26,8 @@ function validateSocksClientOptions(options, acceptedCommands = ['connect', 'bin
if (!isValidSocksProxy(options.proxy)) {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsProxy, options);
}
// Validate custom auth (if set)
validateCustomProxyAuth(options.proxy, options);
// Check timeout
if (options.timeout && !isValidTimeoutValue(options.timeout)) {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsTimeout, options);
@ -61,6 +63,8 @@ function validateSocksClientChainOptions(options) {
if (!isValidSocksProxy(proxy)) {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsProxy, options);
}
// Validate custom auth (if set)
validateCustomProxyAuth(proxy, options);
});
// Check timeout
if (options.timeout && !isValidTimeoutValue(options.timeout)) {
@ -68,6 +72,29 @@ function validateSocksClientChainOptions(options) {
}
}
exports.validateSocksClientChainOptions = validateSocksClientChainOptions;
function validateCustomProxyAuth(proxy, options) {
if (proxy.custom_auth_method !== undefined) {
// Invalid auth method range
if (proxy.custom_auth_method < constants_1.SOCKS5_CUSTOM_AUTH_START ||
proxy.custom_auth_method > constants_1.SOCKS5_CUSTOM_AUTH_END) {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsCustomAuthRange, options);
}
// Missing custom_auth_request_handler
if (proxy.custom_auth_request_handler === undefined ||
typeof proxy.custom_auth_request_handler !== 'function') {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsCustomAuthOptions, options);
}
// Missing custom_auth_response_size
if (proxy.custom_auth_response_size === undefined) {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsCustomAuthOptions, options);
}
// Missing/invalid custom_auth_response_handler
if (proxy.custom_auth_response_handler === undefined ||
typeof proxy.custom_auth_response_handler !== 'function') {
throw new util_1.SocksClientError(constants_1.ERRORS.InvalidSocksClientOptionsCustomAuthOptions, options);
}
}
}
/**
* Validates a SocksRemoteHost
* @param remoteHost { SocksRemoteHost }

View File

@ -1 +1 @@
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/common/helpers.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/common/helpers.ts"],"names":[],"mappings":"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"}

View File

@ -1,7 +1,7 @@
{
"name": "socks",
"private": false,
"version": "2.5.1",
"version": "2.6.0",
"description": "Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality.",
"main": "build/index.js",
"typings": "typings/index.d.ts",
@ -34,17 +34,17 @@
"readmeFilename": "README.md",
"devDependencies": {
"@types/ip": "1.1.0",
"@types/mocha": "^8.0.3",
"@types/node": "^14.14.3",
"@types/mocha": "^8.2.1",
"@types/node": "^14.14.35",
"coveralls": "3.1.0",
"mocha": "^8.2.0",
"mocha": "^8.3.2",
"nyc": "15.1.0",
"prettier": "^2.1.2",
"prettier": "^2.2.1",
"socks5-server": "^0.1.1",
"ts-node": "^9.0.0",
"ts-node": "^9.1.1",
"tslint": "^6.1.3",
"tslint-config-airbnb": "^5.11.2",
"typescript": "^4.0.3"
"typescript": "^4.2.3"
},
"dependencies": {
"ip": "^1.1.5",
@ -57,7 +57,7 @@
"coverage": "NODE_ENV=test nyc npm test",
"coveralls": "NODE_ENV=test nyc npm test && nyc report --reporter=text-lcov | coveralls",
"lint": "tslint --project tsconfig.json 'src/**/*.ts'",
"build": "rm -rf build typings && tslint --project tsconfig.json && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p ."
"build": "rm -rf build typings && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p ."
},
"nyc": {
"extension": [

View File

@ -22,6 +22,7 @@ declare class SocksClient extends EventEmitter implements SocksClient {
private state;
private receiveBuffer;
private nextRequiredPacketBufferSize;
private socks5ChosenAuthType;
private onDataReceived;
private onClose;
private onError;
@ -132,6 +133,10 @@ declare class SocksClient extends EventEmitter implements SocksClient {
* Note: No auth and user/pass are currently supported.
*/
private sendSocks5UserPassAuthentication;
private sendSocks5CustomAuthentication;
private handleSocks5CustomAuthHandshakeResponse;
private handleSocks5AuthenticationNoAuthHandshakeResponse;
private handleSocks5AuthenticationUserPassHandshakeResponse;
/**
* Handles Socks v5 auth handshake response.
* @param data

View File

@ -13,6 +13,8 @@ declare const ERRORS: {
InvalidSocksClientOptionsProxy: string;
InvalidSocksClientOptionsTimeout: string;
InvalidSocksClientOptionsProxiesLength: string;
InvalidSocksClientOptionsCustomAuthRange: string;
InvalidSocksClientOptionsCustomAuthOptions: string;
NegotiationError: string;
SocketClosed: string;
ProxyConnectionTimedOut: string;
@ -57,6 +59,9 @@ declare enum Socks5Auth {
GSSApi = 1,
UserPass = 2
}
declare const SOCKS5_CUSTOM_AUTH_START = 128;
declare const SOCKS5_CUSTOM_AUTH_END = 254;
declare const SOCKS5_NO_ACCEPTABLE_AUTH = 255;
declare enum Socks5Response {
Granted = 0,
Failure = 1,
@ -98,6 +103,10 @@ declare type SocksProxy = RequireOnlyOne<{
type: SocksProxyType;
userId?: string;
password?: string;
custom_auth_method?: number;
custom_auth_request_handler?: () => Promise<Buffer>;
custom_auth_response_size?: number;
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
}, 'host' | 'ipaddress'>;
/**
* Represents a remote host
@ -138,4 +147,4 @@ interface SocksUDPFrameDetails {
remoteHost: SocksRemoteHost;
data: Buffer;
}
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails, SOCKS_INCOMING_PACKET_SIZES, };
export { DEFAULT_TIMEOUT, ERRORS, SocksProxyType, SocksCommand, Socks4Response, Socks5Auth, Socks5HostType, Socks5Response, SocksClientState, SocksProxy, SocksRemoteHost, SocksCommandOption, SocksClientOptions, SocksClientChainOptions, SocksClientEstablishedEvent, SocksClientBoundEvent, SocksUDPFrameDetails, SOCKS_INCOMING_PACKET_SIZES, SOCKS5_CUSTOM_AUTH_START, SOCKS5_CUSTOM_AUTH_END, SOCKS5_NO_ACCEPTABLE_AUTH, };

View File

@ -1,5 +1,5 @@
{
"version": "7.7.0",
"version": "7.7.4",
"name": "npm",
"description": "a package manager for JavaScript",
"keywords": [
@ -59,7 +59,7 @@
"columnify": "~1.5.4",
"glob": "^7.1.4",
"graceful-fs": "^4.2.6",
"hosted-git-info": "^4.0.1",
"hosted-git-info": "^4.0.2",
"ini": "^2.0.0",
"init-package-json": "^2.0.2",
"is-cidr": "^4.0.2",

View File

@ -32,6 +32,7 @@ Array [
"commit-hooks",
"depth",
"description",
"dev",
"diff",
"diff-ignore-all-space",
"diff-name-only",

View File

@ -64,7 +64,7 @@ registry and all registries configured for scopes. See the documentation for
#### \`audit-level\`
* Default: null
* Type: "low", "moderate", "high", "critical", "none", or null
* Type: "info", "low", "moderate", "high", "critical", "none", or null
The minimum level of vulnerability for \`npm audit\` to exit with a non-zero
exit code.
@ -1261,6 +1261,14 @@ What authentication strategy to use with \`adduser\`/\`login\`.
\`--cache-min=9999 (or bigger)\` is an alias for \`--prefer-offline\`.
#### \`dev\`
* Default: false
* Type: Boolean
* DEPRECATED: Please use --include=dev instead.
Alias for \`--include=dev\`.
#### \`init.author.email\`
* Default: ""
@ -1330,8 +1338,8 @@ Alias for --include=optional or --omit=optional
#### \`production\`
* Default: false
* Type: Boolean
* Default: null
* Type: null or Boolean
* DEPRECATED: Use \`--omit=dev\` instead.
Alias for \`--omit=dev\`

View File

@ -204,7 +204,7 @@ All commands:
npm audit [fix]
Options:
[--dry-run] [-f|--force] [--json] [--package-lock-only] [--production]
[--audit-level <info|low|moderate|high|critical|none>] [--dry-run] [-f|--force] [--json] [--package-lock-only] [--production]
Run "npm help audit" for more info

View File

@ -54,6 +54,7 @@ const cliConfig = {
const npm = {
log: {
warn: () => null,
info: () => null,
enableProgress: () => null,
disableProgress: () => null,
@ -93,6 +94,22 @@ t.test('config no args', t => {
})
})
t.test('config ignores workspaces', t => {
npm.log.warn = (title, msg) => {
t.equal(title, 'config', 'should warn with expected title')
t.equal(
msg,
'This command does not support workspaces.',
'should warn with unsupported option msg'
)
}
config.execWorkspaces([], [], (err) => {
t.match(err, /usage instructions/, 'should not error out when workspaces are defined')
npm.log.warn = () => null
t.end()
})
})
t.test('config list', t => {
t.plan(2)
@ -389,7 +406,7 @@ t.test('config set invalid key', t => {
npm.config.validate = npmConfigValidate
delete npm.config.save
delete npm.config.set
delete npm.log.warn
npm.log.warn = () => null
})
config.exec(['set', 'foo', 'bar'], (err) => {

View File

@ -32,7 +32,7 @@ test('should install using Arborist', (t) => {
const npm = mockNpm({
config: { dev: true },
flatOptions: { global: false },
flatOptions: { global: false, auditLevel: 'low' },
globalDir: 'path/to/node_modules/',
prefix: 'foo',
})
@ -42,7 +42,9 @@ test('should install using Arborist', (t) => {
install.exec(['fizzbuzz'], er => {
if (er)
throw er
t.match(ARB_ARGS, { global: false, path: 'foo' })
t.match(ARB_ARGS,
{ global: false, path: 'foo', auditLevel: null },
'Arborist gets correct args and ignores auditLevel')
t.equal(REIFY_CALLED, true, 'called reify')
t.strictSame(SCRIPTS, [], 'no scripts when adding dep')
t.end()

View File

@ -2,6 +2,43 @@ const test = require('tap')
const requireInject = require('require-inject')
const parseJSON = require('json-parse-even-better-errors')
test.test('completion', t => {
const SetScript = requireInject('../../lib/set-script.js')
const emptyDir = t.testdir()
t.test('already have a script name', async t => {
const setScript = new SetScript({localPrefix: emptyDir})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}})
t.equal(res, undefined)
t.end()
})
t.test('no package.json', async t => {
const setScript = new SetScript({localPrefix: emptyDir})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, [])
t.end()
})
t.test('has package.json, no scripts', async t => {
const localPrefix = t.testdir({
'package.json': JSON.stringify({}),
})
const setScript = new SetScript({localPrefix})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, [])
t.end()
})
t.test('has package.json, with scripts', async t => {
const localPrefix = t.testdir({
'package.json': JSON.stringify({
scripts: { hello: 'echo hello', world: 'echo world' },
}),
})
const setScript = new SetScript({localPrefix})
const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}})
t.strictSame(res, ['hello', 'world'])
t.end()
})
t.end()
})
test.test('fails on invalid arguments', (t) => {
const SetScript = requireInject('../../lib/set-script.js', {
npmlog: {},

View File

@ -22,6 +22,7 @@ const uninstall = new Uninstall(npm)
t.afterEach(cb => {
npm.globalDir = ''
npm.prefix = ''
npm.localPrefix = ''
npm.flatOptions.global = false
npm.flatOptions.prefix = ''
cb()
@ -85,7 +86,7 @@ t.test('remove single installed lib', t => {
const b = resolve(path, 'node_modules/b')
t.ok(() => fs.statSync(b))
npm.config.set('prefix', path)
npm.localPrefix = path
uninstall.exec(['b'], err => {
if (err)
@ -148,7 +149,7 @@ t.test('remove multiple installed libs', t => {
t.ok(() => fs.statSync(a))
t.ok(() => fs.statSync(b))
npm.config.set('prefix', path)
npm.localPrefix = path
uninstall.exec(['b'], err => {
if (err)
@ -196,7 +197,6 @@ t.test('no args global', t => {
npm.localPrefix = resolve(path, 'projects', 'a')
npm.globalDir = resolve(path, 'lib', 'node_modules')
npm.config.set('global', true)
npm.config.set('prefix', path)
const a = resolve(path, 'lib/node_modules/a')
t.ok(() => fs.statSync(a))

View File

@ -10,6 +10,7 @@ const config = {
const noop = () => null
const npm = mockNpm({
globalDir: '',
log: noop,
config,
prefix: '',
})
@ -38,7 +39,7 @@ t.test('no args', t => {
constructor (args) {
t.deepEqual(
args,
{ ...npm.flatOptions, path: npm.prefix },
{ ...npm.flatOptions, path: npm.prefix, log: noop },
'should call arborist contructor with expected args'
)
}
@ -72,7 +73,7 @@ t.test('with args', t => {
constructor (args) {
t.deepEqual(
args,
{ ...npm.flatOptions, path: npm.prefix },
{ ...npm.flatOptions, path: npm.prefix, log: noop },
'should call arborist contructor with expected args'
)
}
@ -140,7 +141,7 @@ t.test('update --global', t => {
const { path, ...opts } = args
t.deepEqual(
opts,
npm.flatOptions,
{ ...npm.flatOptions, log: noop },
'should call arborist contructor with expected options'
)

View File

@ -194,18 +194,26 @@ t.test('flatteners that populate flat.omit array', t => {
// ignored if setting is not dev or development
obj.also = 'ignored'
definitions.also.flatten('also', obj, flat)
t.strictSame(obj, {also: 'ignored'}, 'nothing done')
t.strictSame(flat, {}, 'nothing done')
t.strictSame(obj, {also: 'ignored', omit: [], include: []}, 'nothing done')
t.strictSame(flat, {omit: []}, 'nothing done')
obj.also = 'development'
definitions.also.flatten('also', obj, flat)
t.strictSame(obj, { also: 'development', include: ['dev'] }, 'marked dev as included')
t.strictSame(obj, {
also: 'development',
omit: [],
include: ['dev'],
}, 'marked dev as included')
t.strictSame(flat, { omit: [] }, 'nothing omitted, so nothing changed')
obj.omit = ['dev', 'optional']
obj.include = []
definitions.also.flatten('also', obj, flat)
t.strictSame(obj, { also: 'development', omit: ['dev', 'optional'], include: ['dev'] }, 'marked dev as included')
t.strictSame(obj, {
also: 'development',
omit: ['optional'],
include: ['dev'],
}, 'marked dev as included')
t.strictSame(flat, { omit: ['optional'] }, 'removed dev from omit')
t.end()
})
@ -237,7 +245,7 @@ t.test('flatteners that populate flat.omit array', t => {
const flat = {}
const obj = { only: 'asdf' }
definitions.only.flatten('only', obj, flat)
t.strictSame(flat, {}, 'ignored if value is not production')
t.strictSame(flat, { omit: [] }, 'ignored if value is not production')
obj.only = 'prod'
definitions.only.flatten('only', obj, flat)
@ -256,18 +264,30 @@ t.test('flatteners that populate flat.omit array', t => {
const obj = { optional: null }
definitions.optional.flatten('optional', obj, flat)
t.strictSame(obj, { optional: null }, 'do nothing by default')
t.strictSame(flat, {}, 'do nothing by default')
t.strictSame(obj, {
optional: null,
omit: [],
include: [],
}, 'do nothing by default')
t.strictSame(flat, { omit: [] }, 'do nothing by default')
obj.optional = true
definitions.optional.flatten('optional', obj, flat)
t.strictSame(obj, {include: ['optional'], optional: true}, 'include optional when set')
t.strictSame(obj, {
omit: [],
optional: true,
include: ['optional'],
}, 'include optional when set')
t.strictSame(flat, {omit: []}, 'nothing to omit in flatOptions')
delete obj.include
obj.optional = false
definitions.optional.flatten('optional', obj, flat)
t.strictSame(obj, {omit: ['optional'], optional: false}, 'omit optional when set false')
t.strictSame(obj, {
omit: ['optional'],
optional: false,
include: [],
}, 'omit optional when set false')
t.strictSame(flat, {omit: ['optional']}, 'omit optional when set false')
t.end()
@ -277,25 +297,49 @@ t.test('flatteners that populate flat.omit array', t => {
const flat = {}
const obj = {production: true}
definitions.production.flatten('production', obj, flat)
t.strictSame(obj, {production: true, omit: ['dev']}, '--production sets --omit=dev')
t.strictSame(obj, {
production: true,
omit: ['dev'],
include: [],
}, '--production sets --omit=dev')
t.strictSame(flat, {omit: ['dev']}, '--production sets --omit=dev')
delete obj.omit
obj.production = false
delete flat.omit
definitions.production.flatten('production', obj, flat)
t.strictSame(obj, {production: false}, '--no-production has no effect')
t.strictSame(flat, {}, '--no-production has no effect')
t.strictSame(obj, {
production: false,
include: ['dev'],
omit: [],
}, '--no-production explicitly includes dev')
t.strictSame(flat, { omit: [] }, '--no-production has no effect')
obj.production = true
obj.include = ['dev']
definitions.production.flatten('production', obj, flat)
t.strictSame(obj, {production: true, include: ['dev'], omit: ['dev']}, 'omit and include dev')
t.strictSame(obj, {
production: true,
include: ['dev'],
omit: [],
}, 'omit and include dev')
t.strictSame(flat, {omit: []}, 'do not omit dev when included')
t.end()
})
t.test('dev', t => {
const flat = {}
const obj = {dev: true}
definitions.dev.flatten('dev', obj, flat)
t.strictSame(obj, {
dev: true,
omit: [],
include: ['dev'],
})
t.end()
})
t.end()
})
@ -695,3 +739,18 @@ t.test('user-agent', t => {
t.equal(flat.userAgent, expectCI)
t.end()
})
t.test('save-prefix', t => {
const obj = {
'save-exact': true,
'save-prefix': '~1.2.3',
}
const flat = {}
definitions['save-prefix']
.flatten('save-prefix', { ...obj, 'save-exact': true }, flat)
t.strictSame(flat, { savePrefix: '' })
definitions['save-prefix']
.flatten('save-prefix', { ...obj, 'save-exact': false }, flat)
t.strictSame(flat, { savePrefix: '~1.2.3' })
t.end()
})

View File

@ -6,6 +6,8 @@ delete process.env.NODE
process.execPath = '/path/to/node'
const obj = {
'save-exact': true,
'save-prefix': 'ignored',
'save-dev': true,
'@foobar:registry': 'https://foo.bar.com/',
'//foo.bar.com:_authToken': 'foobarbazquuxasdf',
@ -15,6 +17,8 @@ const obj = {
const flat = flatten(obj)
t.strictSame(flat, {
saveType: 'dev',
saveExact: true,
savePrefix: '',
'@foobar:registry': 'https://foo.bar.com/',
'//foo.bar.com:_authToken': 'foobarbazquuxasdf',
npmBin: '/path/to/npm',
@ -26,6 +30,8 @@ t.strictSame(flat, {
process.env.NODE = '/usr/local/bin/node.exe'
flatten({ 'save-dev': false }, flat)
t.strictSame(flat, {
saveExact: true,
savePrefix: '',
'@foobar:registry': 'https://foo.bar.com/',
'//foo.bar.com:_authToken': 'foobarbazquuxasdf',
npmBin: '/path/to/npm',