A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/npm/cli/commit/b153927feca3717598440b82a705281d652b4bf0 below:

npm-package-arg@12.0.2 · npm/cli@b153927 · GitHub

1 1

'use strict'

2 -

module.exports = npa

3 -

module.exports.resolve = resolve

4 -

module.exports.toPurl = toPurl

5 -

module.exports.Result = Result

6 2 7 -

const { URL } = require('url')

3 +

const isWindows = process.platform === 'win32'

4 + 5 +

const { URL } = require('node:url')

6 +

// We need to use path/win32 so that we get consistent results in tests, but this also means we need to manually convert backslashes to forward slashes when generating file: urls with paths.

7 +

const path = isWindows ? require('node:path/win32') : require('node:path')

8 +

const { homedir } = require('node:os')

8 9

const HostedGit = require('hosted-git-info')

9 10

const semver = require('semver')

10 -

const path = global.FAKE_WINDOWS ? require('path').win32 : require('path')

11 11

const validatePackageName = require('validate-npm-package-name')

12 -

const { homedir } = require('os')

13 12

const { log } = require('proc-log')

14 13 15 -

const isWindows = process.platform === 'win32' || global.FAKE_WINDOWS

16 14

const hasSlashes = isWindows ? /\\|[/]/ : /[/]/

17 15

const isURL = /^(?:git[+])?[a-z]+:/i

18 16

const isGit = /^[^@]+@[^:.]+\.[^:]+:.+$/i

19 -

const isFilename = /[.](?:tgz|tar.gz|tar)$/i

17 +

const isFileType = /[.](?:tgz|tar.gz|tar)$/i

20 18

const isPortNumber = /:[0-9]+(\/|$)/i

19 +

const isWindowsFile = /^(?:[.]|~[/]|[/\\]|[a-zA-Z]:)/

20 +

const isPosixFile = /^(?:[.]|~[/]|[/]|[a-zA-Z]:)/

21 +

const defaultRegistry = 'https://registry.npmjs.org'

21 22 22 23

function npa (arg, where) {

23 24

let name

@@ -31,13 +32,14 @@ function npa (arg, where) {

31 32

return npa(arg.raw, where || arg.where)

32 33

}

33 34

}

34 -

const nameEndsAt = arg[0] === '@' ? arg.slice(1).indexOf('@') + 1 : arg.indexOf('@')

35 +

const nameEndsAt = arg.indexOf('@', 1) // Skip possible leading @

35 36

const namePart = nameEndsAt > 0 ? arg.slice(0, nameEndsAt) : arg

36 37

if (isURL.test(arg)) {

37 38

spec = arg

38 39

} else if (isGit.test(arg)) {

39 40

spec = `git+ssh://${arg}`

40 -

} else if (namePart[0] !== '@' && (hasSlashes.test(namePart) || isFilename.test(namePart))) {

41 +

// eslint-disable-next-line max-len

42 +

} else if (!namePart.startsWith('@') && (hasSlashes.test(namePart) || isFileType.test(namePart))) {

41 43

spec = arg

42 44

} else if (nameEndsAt > 0) {

43 45

name = namePart

@@ -54,7 +56,27 @@ function npa (arg, where) {

54 56

return resolve(name, spec, where, arg)

55 57

}

56 58 57 -

const isFilespec = isWindows ? /^(?:[.]|~[/]|[/\\]|[a-zA-Z]:)/ : /^(?:[.]|~[/]|[/]|[a-zA-Z]:)/

59 +

function isFileSpec (spec) {

60 +

if (!spec) {

61 +

return false

62 +

}

63 +

if (spec.toLowerCase().startsWith('file:')) {

64 +

return true

65 +

}

66 +

if (isWindows) {

67 +

return isWindowsFile.test(spec)

68 +

}

69 +

// We never hit this in windows tests, obviously

70 +

/* istanbul ignore next */

71 +

return isPosixFile.test(spec)

72 +

}

73 + 74 +

function isAliasSpec (spec) {

75 +

if (!spec) {

76 +

return false

77 +

}

78 +

return spec.toLowerCase().startsWith('npm:')

79 +

}

58 80 59 81

function resolve (name, spec, where, arg) {

60 82

const res = new Result({

@@ -65,12 +87,16 @@ function resolve (name, spec, where, arg) {

65 87

})

66 88 67 89

if (name) {

68 -

res.setName(name)

90 +

res.name = name

69 91

}

70 92 71 -

if (spec && (isFilespec.test(spec) || /^file:/i.test(spec))) {

93 +

if (!where) {

94 +

where = process.cwd()

95 +

}

96 + 97 +

if (isFileSpec(spec)) {

72 98

return fromFile(res, where)

73 -

} else if (spec && /^npm:/i.test(spec)) {

99 +

} else if (isAliasSpec(spec)) {

74 100

return fromAlias(res, where)

75 101

}

76 102

@@ -82,15 +108,13 @@ function resolve (name, spec, where, arg) {

82 108

return fromHostedGit(res, hosted)

83 109

} else if (spec && isURL.test(spec)) {

84 110

return fromURL(res)

85 -

} else if (spec && (hasSlashes.test(spec) || isFilename.test(spec))) {

111 +

} else if (spec && (hasSlashes.test(spec) || isFileType.test(spec))) {

86 112

return fromFile(res, where)

87 113

} else {

88 114

return fromRegistry(res)

89 115

}

90 116

}

91 117 92 -

const defaultRegistry = 'https://registry.npmjs.org'

93 - 94 118

function toPurl (arg, reg = defaultRegistry) {

95 119

const res = npa(arg)

96 120

@@ -128,60 +152,62 @@ function invalidPurlType (type, raw) {

128 152

return err

129 153

}

130 154 131 -

function Result (opts) {

132 -

this.type = opts.type

133 -

this.registry = opts.registry

134 -

this.where = opts.where

135 -

if (opts.raw == null) {

136 -

this.raw = opts.name ? opts.name + '@' + opts.rawSpec : opts.rawSpec

137 -

} else {

138 -

this.raw = opts.raw

155 +

class Result {

156 +

constructor (opts) {

157 +

this.type = opts.type

158 +

this.registry = opts.registry

159 +

this.where = opts.where

160 +

if (opts.raw == null) {

161 +

this.raw = opts.name ? `${opts.name}@${opts.rawSpec}` : opts.rawSpec

162 +

} else {

163 +

this.raw = opts.raw

164 +

}

165 +

this.name = undefined

166 +

this.escapedName = undefined

167 +

this.scope = undefined

168 +

this.rawSpec = opts.rawSpec || ''

169 +

this.saveSpec = opts.saveSpec

170 +

this.fetchSpec = opts.fetchSpec

171 +

if (opts.name) {

172 +

this.setName(opts.name)

173 +

}

174 +

this.gitRange = opts.gitRange

175 +

this.gitCommittish = opts.gitCommittish

176 +

this.gitSubdir = opts.gitSubdir

177 +

this.hosted = opts.hosted

139 178

}

140 179 141 -

this.name = undefined

142 -

this.escapedName = undefined

143 -

this.scope = undefined

144 -

this.rawSpec = opts.rawSpec || ''

145 -

this.saveSpec = opts.saveSpec

146 -

this.fetchSpec = opts.fetchSpec

147 -

if (opts.name) {

148 -

this.setName(opts.name)

149 -

}

150 -

this.gitRange = opts.gitRange

151 -

this.gitCommittish = opts.gitCommittish

152 -

this.gitSubdir = opts.gitSubdir

153 -

this.hosted = opts.hosted

154 -

}

180 +

// TODO move this to a getter/setter in a semver major

181 +

setName (name) {

182 +

const valid = validatePackageName(name)

183 +

if (!valid.validForOldPackages) {

184 +

throw invalidPackageName(name, valid, this.raw)

185 +

}

155 186 156 -

Result.prototype.setName = function (name) {

157 -

const valid = validatePackageName(name)

158 -

if (!valid.validForOldPackages) {

159 -

throw invalidPackageName(name, valid, this.raw)

187 +

this.name = name

188 +

this.scope = name[0] === '@' ? name.slice(0, name.indexOf('/')) : undefined

189 +

// scoped packages in couch must have slash url-encoded, e.g. @foo%2Fbar

190 +

this.escapedName = name.replace('/', '%2f')

191 +

return this

160 192

}

161 193 162 -

this.name = name

163 -

this.scope = name[0] === '@' ? name.slice(0, name.indexOf('/')) : undefined

164 -

// scoped packages in couch must have slash url-encoded, e.g. @foo%2Fbar

165 -

this.escapedName = name.replace('/', '%2f')

166 -

return this

167 -

}

168 - 169 -

Result.prototype.toString = function () {

170 -

const full = []

171 -

if (this.name != null && this.name !== '') {

172 -

full.push(this.name)

173 -

}

174 -

const spec = this.saveSpec || this.fetchSpec || this.rawSpec

175 -

if (spec != null && spec !== '') {

176 -

full.push(spec)

194 +

toString () {

195 +

const full = []

196 +

if (this.name != null && this.name !== '') {

197 +

full.push(this.name)

198 +

}

199 +

const spec = this.saveSpec || this.fetchSpec || this.rawSpec

200 +

if (spec != null && spec !== '') {

201 +

full.push(spec)

202 +

}

203 +

return full.length ? full.join('@') : this.raw

177 204

}

178 -

return full.length ? full.join('@') : this.raw

179 -

}

180 205 181 -

Result.prototype.toJSON = function () {

182 -

const result = Object.assign({}, this)

183 -

delete result.hosted

184 -

return result

206 +

toJSON () {

207 +

const result = Object.assign({}, this)

208 +

delete result.hosted

209 +

return result

210 +

}

185 211

}

186 212 187 213

// sets res.gitCommittish, res.gitRange, and res.gitSubdir

@@ -228,25 +254,67 @@ function setGitAttrs (res, committish) {

228 254

}

229 255

}

230 256 231 -

function fromFile (res, where) {

232 -

if (!where) {

233 -

where = process.cwd()

257 +

// Taken from: EncodePathChars and lookup_table in src/node_url.cc

258 +

// url.pathToFileURL only returns absolute references. We can't use it to encode paths.

259 +

// encodeURI mangles windows paths. We can't use it to encode paths.

260 +

// Under the hood, url.pathToFileURL does a limited set of encoding, with an extra windows step, and then calls path.resolve.

261 +

// The encoding node does without path.resolve is not available outside of the source, so we are recreating it here.

262 +

const encodedPathChars = new Map([

263 +

['\0', '%00'],

264 +

['\t', '%09'],

265 +

['\n', '%0A'],

266 +

['\r', '%0D'],

267 +

[' ', '%20'],

268 +

['"', '%22'],

269 +

['#', '%23'],

270 +

['%', '%25'],

271 +

['?', '%3F'],

272 +

['[', '%5B'],

273 +

['\\', isWindows ? '/' : '%5C'],

274 +

[']', '%5D'],

275 +

['^', '%5E'],

276 +

['|', '%7C'],

277 +

['~', '%7E'],

278 +

])

279 + 280 +

function pathToFileURL (str) {

281 +

let result = ''

282 +

for (let i = 0; i < str.length; i++) {

283 +

result = `${result}${encodedPathChars.get(str[i]) ?? str[i]}`

284 +

}

285 +

if (result.startsWith('file:')) {

286 +

return result

234 287

}

235 -

res.type = isFilename.test(res.rawSpec) ? 'file' : 'directory'

288 +

return `file:${result}`

289 +

}

290 + 291 +

function fromFile (res, where) {

292 +

res.type = isFileType.test(res.rawSpec) ? 'file' : 'directory'

236 293

res.where = where

237 294 238 -

// always put the '/' on where when resolving urls, or else

239 -

// file:foo from /path/to/bar goes to /path/to/foo, when we want

240 -

// it to be /path/to/bar/foo

295 +

let rawSpec = pathToFileURL(res.rawSpec)

296 + 297 +

if (rawSpec.startsWith('file:/')) {

298 +

// XXX backwards compatibility lack of compliance with RFC 8089

299 + 300 +

// turn file://path into file:/path

301 +

if (/^file:\/\/[^/]/.test(rawSpec)) {

302 +

rawSpec = `file:/${rawSpec.slice(5)}`

303 +

}

304 + 305 +

// turn file:/../path into file:../path

306 +

// for 1 or 3 leading slashes (2 is already ruled out from handling file:// explicitly above)

307 +

if (/^\/{1,3}\.\.?(\/|$)/.test(rawSpec.slice(5))) {

308 +

rawSpec = rawSpec.replace(/^file:\/{1,3}/, 'file:')

309 +

}

310 +

}

241 311 242 -

let specUrl

243 312

let resolvedUrl

244 -

const prefix = (!/^file:/.test(res.rawSpec) ? 'file:' : '')

245 -

const rawWithPrefix = prefix + res.rawSpec

246 -

let rawNoPrefix = rawWithPrefix.replace(/^file:/, '')

313 +

let specUrl

247 314

try {

248 -

resolvedUrl = new URL(rawWithPrefix, `file://${path.resolve(where)}/`)

249 -

specUrl = new URL(rawWithPrefix)

315 +

// always put the '/' on "where", or else file:foo from /path/to/bar goes to /path/to/foo, when we want it to be /path/to/bar/foo

316 +

resolvedUrl = new URL(rawSpec, `${pathToFileURL(path.resolve(where))}/`)

317 +

specUrl = new URL(rawSpec)

250 318

} catch (originalError) {

251 319

const er = new Error('Invalid file: URL, must comply with RFC 8089')

252 320

throw Object.assign(er, {

@@ -257,24 +325,6 @@ function fromFile (res, where) {

257 325

})

258 326

}

259 327 260 -

// XXX backwards compatibility lack of compliance with RFC 8089

261 -

if (resolvedUrl.host && resolvedUrl.host !== 'localhost') {

262 -

const rawSpec = res.rawSpec.replace(/^file:\/\//, 'file:///')

263 -

resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`)

264 -

specUrl = new URL(rawSpec)

265 -

rawNoPrefix = rawSpec.replace(/^file:/, '')

266 -

}

267 -

// turn file:/../foo into file:../foo

268 -

// for 1, 2 or 3 leading slashes since we attempted

269 -

// in the previous step to make it a file protocol url with a leading slash

270 -

if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) {

271 -

const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:')

272 -

resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`)

273 -

specUrl = new URL(rawSpec)

274 -

rawNoPrefix = rawSpec.replace(/^file:/, '')

275 -

}

276 -

// XXX end RFC 8089 violation backwards compatibility section

277 - 278 328

// turn /C:/blah into just C:/blah on windows

279 329

let specPath = decodeURIComponent(specUrl.pathname)

280 330

let resolvedPath = decodeURIComponent(resolvedUrl.pathname)

@@ -288,13 +338,21 @@ function fromFile (res, where) {

288 338

if (/^\/~(\/|$)/.test(specPath)) {

289 339

res.saveSpec = `file:${specPath.substr(1)}`

290 340

resolvedPath = path.resolve(homedir(), specPath.substr(3))

291 -

} else if (!path.isAbsolute(rawNoPrefix)) {

341 +

} else if (!path.isAbsolute(rawSpec.slice(5))) {

292 342

res.saveSpec = `file:${path.relative(where, resolvedPath)}`

293 343

} else {

294 344

res.saveSpec = `file:${path.resolve(resolvedPath)}`

295 345

}

296 346 297 347

res.fetchSpec = path.resolve(where, resolvedPath)

348 +

// re-normalize the slashes in saveSpec due to node:path/win32 behavior in windows

349 +

res.saveSpec = res.saveSpec.split('\\').join('/')

350 +

// Ignoring because this only happens in windows

351 +

/* istanbul ignore next */

352 +

if (res.saveSpec.startsWith('file://')) {

353 +

// normalization of \\win32\root paths can cause a double / which we don't want

354 +

res.saveSpec = `file:/${res.saveSpec.slice(7)}`

355 +

}

298 356

return res

299 357

}

300 358

@@ -416,3 +474,8 @@ function fromRegistry (res) {

416 474

}

417 475

return res

418 476

}

477 + 478 +

module.exports = npa

479 +

module.exports.resolve = resolve

480 +

module.exports.toPurl = toPurl

481 +

module.exports.Result = Result


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4