Skip to content

Commit 2e47537

Browse files
committed
deps: @npmcli/[email protected]
1 parent a5eb5dd commit 2e47537

File tree

8 files changed

+291
-46
lines changed

8 files changed

+291
-46
lines changed

DEPENDENCIES.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ graph LR;
223223
npmcli-mock-registry-->pacote;
224224
npmcli-package-json-->hosted-git-info;
225225
npmcli-package-json-->json-parse-even-better-errors;
226-
npmcli-package-json-->normalize-package-data;
227226
npmcli-package-json-->npmcli-git["@npmcli/git"];
228227
npmcli-package-json-->proc-log;
229228
npmcli-package-json-->semver;
@@ -676,10 +675,10 @@ graph LR;
676675
npmcli-package-json-->glob;
677676
npmcli-package-json-->hosted-git-info;
678677
npmcli-package-json-->json-parse-even-better-errors;
679-
npmcli-package-json-->normalize-package-data;
680678
npmcli-package-json-->npmcli-git["@npmcli/git"];
681679
npmcli-package-json-->proc-log;
682680
npmcli-package-json-->semver;
681+
npmcli-package-json-->validate-npm-package-license;
683682
npmcli-promise-spawn-->which;
684683
npmcli-query-->postcss-selector-parser;
685684
npmcli-run-script-->node-gyp;
@@ -802,5 +801,5 @@ packages higher up the chain.
802801
- @npmcli/package-json, npm-registry-fetch
803802
- @npmcli/git, make-fetch-happen
804803
- @npmcli/installed-package-contents, npm-pick-manifest, cacache, promzard
805-
- @npmcli/docs, @npmcli/fs, npm-bundled, npm-install-checks, npm-package-arg, normalize-package-data, unique-filename, npm-packlist, bin-links, nopt, parse-conflict-json, read-package-json-fast, @npmcli/mock-globals, read
804+
- @npmcli/docs, @npmcli/fs, npm-bundled, npm-install-checks, npm-package-arg, unique-filename, npm-packlist, bin-links, nopt, parse-conflict-json, read-package-json-fast, @npmcli/mock-globals, read, normalize-package-data
806805
- @npmcli/eslint-config, @npmcli/template-oss, ignore-walk, semver, npm-normalize-package-bin, @npmcli/name-from-folder, @npmcli/promise-spawn, ini, hosted-git-info, proc-log, validate-npm-package-name, json-parse-even-better-errors, fs-minipass, ssri, unique-slug, @npmcli/node-gyp, @npmcli/redact, @npmcli/agent, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, proggy, minify-registry-metadata, mute-stream, npm-audit-report, npm-user-validate

node_modules/@npmcli/package-json/lib/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class PackageJson {
4141
'binRefs',
4242
'bundleDependencies',
4343
'bundleDependenciesFalse',
44+
'fixName',
4445
'fixNameField',
4546
'fixVersionField',
4647
'fixRepositoryField',
@@ -252,7 +253,9 @@ class PackageJson {
252253
.replace(/\n/g, eol)
253254

254255
if (fileContent.trim() !== this.#readFileContent.trim()) {
255-
return await writeFile(this.filename, fileContent)
256+
const written = await writeFile(this.filename, fileContent)
257+
this.#readFileContent = fileContent
258+
return written
256259
}
257260
}
258261

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// Originally normalize-package-data
2+
3+
const url = require('node:url')
4+
const hostedGitInfo = require('hosted-git-info')
5+
const validateLicense = require('validate-npm-package-license')
6+
7+
const typos = {
8+
dependancies: 'dependencies',
9+
dependecies: 'dependencies',
10+
depdenencies: 'dependencies',
11+
devEependencies: 'devDependencies',
12+
depends: 'dependencies',
13+
'dev-dependencies': 'devDependencies',
14+
devDependences: 'devDependencies',
15+
devDepenencies: 'devDependencies',
16+
devdependencies: 'devDependencies',
17+
repostitory: 'repository',
18+
repo: 'repository',
19+
prefereGlobal: 'preferGlobal',
20+
hompage: 'homepage',
21+
hampage: 'homepage',
22+
autohr: 'author',
23+
autor: 'author',
24+
contributers: 'contributors',
25+
publicationConfig: 'publishConfig',
26+
script: 'scripts',
27+
}
28+
29+
const isEmail = str => str.includes('@') && (str.indexOf('@') < str.lastIndexOf('.'))
30+
31+
// Extracts description from contents of a readme file in markdown format
32+
function extractDescription (description) {
33+
// the first block of text before the first heading that isn't the first line heading
34+
const lines = description.trim().split('\n')
35+
let start = 0
36+
// skip initial empty lines and lines that start with #
37+
while (lines[start]?.trim().match(/^(#|$)/)) {
38+
start++
39+
}
40+
let end = start + 1
41+
// keep going till we get to the end or an empty line
42+
while (end < lines.length && lines[end].trim()) {
43+
end++
44+
}
45+
return lines.slice(start, end).join(' ').trim()
46+
}
47+
48+
function stringifyPerson (person) {
49+
if (typeof person !== 'string') {
50+
const name = person.name || ''
51+
const u = person.url || person.web
52+
const wrappedUrl = u ? (' (' + u + ')') : ''
53+
const e = person.email || person.mail
54+
const wrappedEmail = e ? (' <' + e + '>') : ''
55+
person = name + wrappedEmail + wrappedUrl
56+
}
57+
const matchedName = person.match(/^([^(<]+)/)
58+
const matchedUrl = person.match(/\(([^()]+)\)/)
59+
const matchedEmail = person.match(/<([^<>]+)>/)
60+
const parsed = {}
61+
if (matchedName?.[0].trim()) {
62+
parsed.name = matchedName[0].trim()
63+
}
64+
if (matchedEmail) {
65+
parsed.email = matchedEmail[1]
66+
}
67+
if (matchedUrl) {
68+
parsed.url = matchedUrl[1]
69+
}
70+
return parsed
71+
}
72+
73+
function normalizeData (data, changes) {
74+
// fixDescriptionField
75+
if (data.description && typeof data.description !== 'string') {
76+
changes?.push(`'description' field should be a string`)
77+
delete data.description
78+
}
79+
if (data.readme && !data.description && data.readme !== 'ERROR: No README data found!') {
80+
data.description = extractDescription(data.readme)
81+
}
82+
if (data.description === undefined) {
83+
delete data.description
84+
}
85+
if (!data.description) {
86+
changes?.push('No description')
87+
}
88+
89+
// fixModulesField
90+
if (data.modules) {
91+
changes?.push(`modules field is deprecated`)
92+
delete data.modules
93+
}
94+
95+
// fixFilesField
96+
const files = data.files
97+
if (files && !Array.isArray(files)) {
98+
changes?.push(`Invalid 'files' member`)
99+
delete data.files
100+
} else if (data.files) {
101+
data.files = data.files.filter(function (file) {
102+
if (!file || typeof file !== 'string') {
103+
changes?.push(`Invalid filename in 'files' list: ${file}`)
104+
return false
105+
} else {
106+
return true
107+
}
108+
})
109+
}
110+
111+
// fixManField
112+
if (data.man && typeof data.man === 'string') {
113+
data.man = [data.man]
114+
}
115+
116+
// fixBugsField
117+
if (!data.bugs && data.repository?.url) {
118+
const hosted = hostedGitInfo.fromUrl(data.repository.url)
119+
if (hosted && hosted.bugs()) {
120+
data.bugs = { url: hosted.bugs() }
121+
}
122+
} else if (data.bugs) {
123+
if (typeof data.bugs === 'string') {
124+
if (isEmail(data.bugs)) {
125+
data.bugs = { email: data.bugs }
126+
/* eslint-disable-next-line node/no-deprecated-api */
127+
} else if (url.parse(data.bugs).protocol) {
128+
data.bugs = { url: data.bugs }
129+
} else {
130+
changes?.push(`Bug string field must be url, email, or {email,url}`)
131+
}
132+
} else {
133+
for (const k in data.bugs) {
134+
if (['web', 'name'].includes(k)) {
135+
changes?.push(`bugs['${k}'] should probably be bugs['url'].`)
136+
data.bugs.url = data.bugs[k]
137+
delete data.bugs[k]
138+
}
139+
}
140+
const oldBugs = data.bugs
141+
data.bugs = {}
142+
if (oldBugs.url) {
143+
/* eslint-disable-next-line node/no-deprecated-api */
144+
if (typeof (oldBugs.url) === 'string' && url.parse(oldBugs.url).protocol) {
145+
data.bugs.url = oldBugs.url
146+
} else {
147+
changes?.push('bugs.url field must be a string url. Deleted.')
148+
}
149+
}
150+
if (oldBugs.email) {
151+
if (typeof (oldBugs.email) === 'string' && isEmail(oldBugs.email)) {
152+
data.bugs.email = oldBugs.email
153+
} else {
154+
changes?.push('bugs.email field must be a string email. Deleted.')
155+
}
156+
}
157+
}
158+
if (!data.bugs.email && !data.bugs.url) {
159+
delete data.bugs
160+
changes?.push('Normalized value of bugs field is an empty object. Deleted.')
161+
}
162+
}
163+
// fixKeywordsField
164+
if (typeof data.keywords === 'string') {
165+
data.keywords = data.keywords.split(/,\s+/)
166+
}
167+
if (data.keywords && !Array.isArray(data.keywords)) {
168+
delete data.keywords
169+
changes?.push(`keywords should be an array of strings`)
170+
} else if (data.keywords) {
171+
data.keywords = data.keywords.filter(function (kw) {
172+
if (typeof kw !== 'string' || !kw) {
173+
changes?.push(`keywords should be an array of strings`)
174+
return false
175+
} else {
176+
return true
177+
}
178+
})
179+
}
180+
// fixBundleDependenciesField
181+
const bdd = 'bundledDependencies'
182+
const bd = 'bundleDependencies'
183+
if (data[bdd] && !data[bd]) {
184+
data[bd] = data[bdd]
185+
delete data[bdd]
186+
}
187+
if (data[bd] && !Array.isArray(data[bd])) {
188+
changes?.push(`Invalid 'bundleDependencies' list. Must be array of package names`)
189+
delete data[bd]
190+
} else if (data[bd]) {
191+
data[bd] = data[bd].filter(function (filtered) {
192+
if (!filtered || typeof filtered !== 'string') {
193+
changes?.push(`Invalid bundleDependencies member: ${filtered}`)
194+
return false
195+
} else {
196+
if (!data.dependencies) {
197+
data.dependencies = {}
198+
}
199+
if (!Object.prototype.hasOwnProperty.call(data.dependencies, filtered)) {
200+
changes?.push(`Non-dependency in bundleDependencies: ${filtered}`)
201+
data.dependencies[filtered] = '*'
202+
}
203+
return true
204+
}
205+
})
206+
}
207+
// fixHomepageField
208+
if (!data.homepage && data.repository && data.repository.url) {
209+
const hosted = hostedGitInfo.fromUrl(data.repository.url)
210+
if (hosted) {
211+
data.homepage = hosted.docs()
212+
}
213+
}
214+
if (data.homepage) {
215+
if (typeof data.homepage !== 'string') {
216+
changes?.push('homepage field must be a string url. Deleted.')
217+
delete data.homepage
218+
} else {
219+
/* eslint-disable-next-line node/no-deprecated-api */
220+
if (!url.parse(data.homepage).protocol) {
221+
data.homepage = 'http://' + data.homepage
222+
}
223+
}
224+
}
225+
// fixReadmeField
226+
if (!data.readme) {
227+
changes?.push('No README data')
228+
data.readme = 'ERROR: No README data found!'
229+
}
230+
// fixLicenseField
231+
const license = data.license || data.licence
232+
if (!license) {
233+
changes?.push('No license field.')
234+
} else if (typeof (license) !== 'string' || license.length < 1 || license.trim() === '') {
235+
changes?.push('license should be a valid SPDX license expression')
236+
} else if (!validateLicense(license).validForNewPackages) {
237+
changes?.push('license should be a valid SPDX license expression')
238+
}
239+
// fixPeople
240+
if (data.author) {
241+
data.author = stringifyPerson(data.author)
242+
}
243+
['maintainers', 'contributors'].forEach(function (set) {
244+
if (!Array.isArray(data[set])) {
245+
return
246+
}
247+
data[set] = data[set].map(stringifyPerson)
248+
})
249+
// fixTypos
250+
for (const d in typos) {
251+
if (Object.prototype.hasOwnProperty.call(data, d)) {
252+
changes?.push(`${d} should probably be ${typos[d]}.`)
253+
}
254+
}
255+
}
256+
257+
module.exports = { normalizeData }

node_modules/@npmcli/package-json/lib/normalize.js

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const clean = require('semver/functions/clean')
33
const fs = require('node:fs/promises')
44
const path = require('node:path')
55
const { log } = require('proc-log')
6+
const moduleBuiltin = require('node:module')
67

78
/**
89
* @type {import('hosted-git-info')}
@@ -144,7 +145,7 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
144145
const pkgId = `${data.name ?? ''}@${data.version ?? ''}`
145146

146147
// name and version are load bearing so we have to clean them up first
147-
if (steps.includes('fixNameField') || steps.includes('normalizeData')) {
148+
if (steps.includes('fixName') || steps.includes('fixNameField') || steps.includes('normalizeData')) {
148149
if (!data.name && !strict) {
149150
changes?.push('Missing "name" field was set to an empty string')
150151
data.name = ''
@@ -170,6 +171,13 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
170171
}
171172
}
172173

174+
if (steps.includes('fixName')) {
175+
// Check for conflicts with builtin modules
176+
if (moduleBuiltin.builtinModules.includes(data.name)) {
177+
log.warn('package-json', pkgId, `Package name "${data.name}" conflicts with a Node.js built-in module name`)
178+
}
179+
}
180+
173181
if (steps.includes('fixVersionField') || steps.includes('normalizeData')) {
174182
// allow "loose" semver 1.0 versions in non-strict mode
175183
// enforce strict semver 2.0 compliance in strict mode
@@ -348,7 +356,6 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
348356
changes?.push(`"readmeFilename" was set to ${readmeFile}`)
349357
}
350358
if (!data.readme) {
351-
// this.warn('missingReadme')
352359
data.readme = 'ERROR: No README data found!'
353360
}
354361
}
@@ -488,7 +495,6 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
488495
// Some steps are isolated so we can do a limited subset of these in `fix`
489496
if (steps.includes('fixRepositoryField') || steps.includes('normalizeData')) {
490497
if (data.repositories) {
491-
/* eslint-disable-next-line max-len */
492498
changes?.push(`"repository" was set to the first entry in "repositories" (${data.repository})`)
493499
data.repository = data.repositories[0]
494500
}
@@ -572,30 +578,10 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
572578
}
573579
}
574580

581+
// TODO some of this is duplicated in other steps here, a future breaking change may be able to remove the duplicates involved in this step
575582
if (steps.includes('normalizeData')) {
576-
const legacyFixer = require('normalize-package-data/lib/fixer.js')
577-
const legacyMakeWarning = require('normalize-package-data/lib/make_warning.js')
578-
legacyFixer.warn = function () {
579-
changes?.push(legacyMakeWarning.apply(null, arguments))
580-
}
581-
582-
const legacySteps = [
583-
'fixDescriptionField',
584-
'fixModulesField',
585-
'fixFilesField',
586-
'fixManField',
587-
'fixBugsField',
588-
'fixKeywordsField',
589-
'fixBundleDependenciesField',
590-
'fixHomepageField',
591-
'fixReadmeField',
592-
'fixLicenseField',
593-
'fixPeople',
594-
'fixTypos',
595-
]
596-
for (const legacyStep of legacySteps) {
597-
legacyFixer[legacyStep](data)
598-
}
583+
const { normalizeData } = require('./normalize-data.js')
584+
normalizeData(data, changes)
599585
}
600586

601587
// Warn if the bin references don't point to anything. This might be better

0 commit comments

Comments
 (0)