Skip to content

Commit 3c1cb66

Browse files
committed
fix: inline bin normalization code
Changes are also now properly reported
1 parent 4743d41 commit 3c1cb66

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

lib/normalize.js

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,70 @@
11
const semver = require('semver')
22
const fs = require('fs/promises')
33
const { glob } = require('glob')
4-
const normalizePackageBin = require('npm-normalize-package-bin')
54
const legacyFixer = require('normalize-package-data/lib/fixer.js')
65
const legacyMakeWarning = require('normalize-package-data/lib/make_warning.js')
76
const path = require('path')
87
const log = require('proc-log')
98
const git = require('@npmcli/git')
109
const hostedGitInfo = require('hosted-git-info')
1110

11+
// used to be npm-normalize-package-bin
12+
function normalizePackageBin (pkg, changes) {
13+
if (pkg.bin) {
14+
if (typeof pkg.bin === 'string' && pkg.name) {
15+
changes?.push('"bin" was converted to an object')
16+
pkg.bin = { [pkg.name]: pkg.bin }
17+
} else if (Array.isArray(pkg.bin)) {
18+
changes?.push('"bin" was converted to an object')
19+
pkg.bin = pkg.bin.reduce((acc, k) => {
20+
acc[path.basename(k)] = k
21+
return acc
22+
}, {})
23+
}
24+
if (typeof pkg.bin === 'object') {
25+
for (const binKey in pkg.bin) {
26+
if (typeof pkg.bin[binKey] !== 'string') {
27+
delete pkg.bin[binKey]
28+
changes?.push(`removed invalid "bin[${binKey}]"`)
29+
continue
30+
}
31+
const base = path.join('/', path.basename(binKey.replace(/\\|:/g, '/'))).slice(1)
32+
if (!base) {
33+
delete pkg.bin[binKey]
34+
changes?.push(`removed invalid "bin[${binKey}]"`)
35+
continue
36+
}
37+
38+
const binTarget = path.join('/', pkg.bin[binKey].replace(/\\/g, '/'))
39+
.replace(/\\/g, '/').slice(1)
40+
41+
if (!binTarget) {
42+
delete pkg.bin[binKey]
43+
changes?.push(`removed invalid "bin[${binKey}]"`)
44+
continue
45+
}
46+
47+
if (base !== binKey) {
48+
delete pkg.bin[binKey]
49+
changes?.push(`"bin[${binKey}]" was renamed to "bin[${base}]"`)
50+
}
51+
if (binTarget !== pkg.bin[binKey]) {
52+
changes?.push(`"bin[${base}]" script name was cleaned`)
53+
}
54+
pkg.bin[base] = binTarget
55+
}
56+
57+
if (Object.keys(pkg.bin).length === 0) {
58+
changes?.push('empty "bin" was removed')
59+
delete pkg.bin
60+
}
61+
62+
return pkg
63+
}
64+
}
65+
delete pkg.bin
66+
}
67+
1268
function isCorrectlyEncodedName (spec) {
1369
return !spec.match(/[/@\s+%:]/) &&
1470
spec === encodeURIComponent(spec)
@@ -257,7 +313,7 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
257313
}
258314

259315
if (steps.includes('bin') || steps.includes('binDir') || steps.includes('binRefs')) {
260-
normalizePackageBin(data)
316+
normalizePackageBin(data, changes)
261317
}
262318

263319
// expand "directories.bin"
@@ -272,7 +328,7 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase })
272328
return acc
273329
}, {})
274330
// *sigh*
275-
normalizePackageBin(data)
331+
normalizePackageBin(data, changes)
276332
}
277333

278334
// populate "gitHead" attribute

tap-snapshots/test/fix.js.test.cjs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,32 @@
55
* Make sure to inspect the output below. Do not ignore changes!
66
*/
77
'use strict'
8+
exports[`test/fix.js TAP with changes binRefs array > must match snapshot 1`] = `
9+
Array [
10+
"\\"bin\\" was converted to an object",
11+
]
12+
`
13+
14+
exports[`test/fix.js TAP with changes binRefs empty bin name > must match snapshot 1`] = `
15+
Array [
16+
"removed invalid \\"bin[/]\\"",
17+
"empty \\"bin\\" was removed",
18+
]
19+
`
20+
21+
exports[`test/fix.js TAP with changes binRefs no bin target > must match snapshot 1`] = `
22+
Array [
23+
"removed invalid \\"bin[test-package]\\"",
24+
"empty \\"bin\\" was removed",
25+
]
26+
`
27+
828
exports[`test/fix.js TAP with changes binRefs scoped name > must match snapshot 1`] = `
9-
Array []
29+
Array [
30+
"\\"bin\\" was converted to an object",
31+
"\\"bin[@npmcli/test-package]\\" was renamed to \\"bin[test-package]\\"",
32+
"\\"bin[test-package]\\" script name was cleaned",
33+
]
1034
`
1135

1236
exports[`test/fix.js TAP with changes bundleDependencies null > must match snapshot 1`] = `

tap-snapshots/test/normalize.js.test.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ exports[`test/normalize.js TAP @npmcli/package-json - with changes cleanup bins
8585
Array [
8686
"Deleted incorrect \\"bundledDependencies\\"",
8787
"Removed invalid \\"scripts\\"",
88+
"\\"bin\\" was converted to an object",
8889
]
8990
`
9091

@@ -99,6 +100,8 @@ exports[`test/normalize.js TAP @npmcli/package-json - with changes cleanup bins
99100
Array [
100101
"Deleted incorrect \\"bundledDependencies\\"",
101102
"Removed invalid \\"scripts\\"",
103+
"removed invalid \\"bin[y]\\"",
104+
"removed invalid \\"bin[z]\\"",
102105
]
103106
`
104107

test/fix.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,27 @@ for (const [name, testFix] of Object.entries(testMethods)) {
208208
const { content } = await testFix(t, testdir)
209209
t.strictSame(content.bin, { 'test-package': '@npmcil/test-package' })
210210
})
211+
t.test('array', async t => {
212+
const testdir = {
213+
'package.json': pkg({ bin: ['@npmcil/test-package'] }),
214+
}
215+
const { content } = await testFix(t, testdir)
216+
t.strictSame(content.bin, { 'test-package': '@npmcil/test-package' })
217+
})
218+
t.test('no bin target', async t => {
219+
const testdir = {
220+
'package.json': pkg({ bin: { 'test-package': '/' } }),
221+
}
222+
const { content } = await testFix(t, testdir)
223+
t.notHas(content, 'bin')
224+
})
225+
t.test('empty bin name', async t => {
226+
const testdir = {
227+
'package.json': pkg({ bin: { '/': 'test-slash' } }),
228+
}
229+
const { content } = await testFix(t, testdir)
230+
t.notHas(content, 'bin')
231+
})
211232
})
212233
t.test('fixDependencies', async t => {
213234
t.test('string dependencies', async t => {

0 commit comments

Comments
 (0)