Skip to content

Commit 32f7f7c

Browse files
committed
feat: allow option to set npm bin in package.json
1 parent 2f7dcfa commit 32f7f7c

File tree

4 files changed

+126
-7
lines changed

4 files changed

+126
-7
lines changed

lib/config.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { relative, dirname, posix, win32 } = require('path')
1+
const { relative, dirname, join, posix, win32 } = require('path')
22
const log = require('proc-log')
33
const { uniq, defaults } = require('lodash')
44
const parseCIVersions = require('./util/parse-ci-versions.js')
@@ -50,13 +50,14 @@ const getConfig = async ({
5050
workspaceRepo,
5151
workspaceModule,
5252
version,
53-
...pkgContent
53+
...pkgConfig // this includes config merged in from root
5454
},
5555
}) => {
5656
const isRoot = root === path
5757
const isLatest = version === LATEST_VERSION
5858
const isDogFood = pkg.name === NAME
5959
const isForce = process.argv.includes('--force')
60+
const rawPkgConfig = getPkgConfig(pkg)
6061

6162
// this is written to ci yml files so it needs to always use posix
6263
const pkgRelPath = makePosix(relative(root, path))
@@ -128,12 +129,25 @@ const getConfig = async ({
128129

129130
// merge the rest of base and pkg content to make the
130131
// full content object
131-
const content = { ...baseContent, ...pkgContent }
132+
const content = { ...baseContent, ...pkgConfig }
132133

133134
// set some defaults on content that can be overwritten unlike
134135
// derived values which are calculated from other config
135136
const contentDefaults = {}
136137

138+
if (content.npmBin && content.npmBin !== baseContent.npmBin) {
139+
// make it relative to each workspace if they did not set the config themselves
140+
if (!rawPkgConfig.npmBin) {
141+
content.npmBin = makePosix(join(relative(path, root), content.npmBin))
142+
}
143+
// a bit of a hack but allow custom node paths or no node path at all
144+
// checks if the first thing has node somewhere in it and if it doesnt
145+
// puts a system node in front of the script
146+
const execPaths = content.npmBin.split(' ')[0].split(posix.sep)
147+
if (execPaths.every(p => p !== 'node')) {
148+
content.npmBin = `node ${content.npmBin}`
149+
}
150+
}
137151
if (Array.isArray(content.ciVersions)) {
138152
const parsed = parseCIVersions(content.ciVersions)
139153
contentDefaults.engines = parsed.engines

lib/content/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ module.exports = {
7373
distPaths: ['bin/', 'lib/'],
7474
ciVersions: ['12.13.0', '12.x', '14.15.0', '14.x', '16.0.0', '16.x'],
7575
lockfile: false,
76+
npmBin: 'npm',
7677
unwantedPackages: [
7778
'eslint',
7879
'eslint-plugin-node',

lib/content/pkg.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
"lint": "eslint \"**/*.js\"",
66
"postlint": "template-oss-check",
77
"template-oss-apply": "template-oss-apply --force",
8-
"lintfix": "npm run lint -- --fix",
9-
"preversion": "npm test",
8+
"lintfix": "{{npmBin}} run lint -- --fix",
9+
"preversion": "{{npmBin}} test",
1010
{{#if pkgPrivate}}
1111
"postversion": "git push origin --follow-tags",
1212
{{else}}
13-
"postversion": "npm publish",
13+
"postversion": "{{npmBin}} publish",
1414
"prepublishOnly": "git push origin --follow-tags",
1515
{{/if}}
1616
"snap": "tap",
1717
"test": "tap",
18-
"posttest": "npm run lint",
18+
"posttest": "{{npmBin}} run lint",
1919
"template-copy": {{{del}}},
2020
"lint:fix": {{{del}}}
2121
},

test/apply/npm-bin.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const t = require('tap')
2+
const { join } = require('path')
3+
const setup = require('../setup.js')
4+
5+
t.test('custom node', async (t) => {
6+
const s = await setup(t, {
7+
ok: true,
8+
package: {
9+
templateOSS: {
10+
npmBin: 'node /path/to/npm',
11+
},
12+
},
13+
})
14+
await s.apply()
15+
const { scripts } = await s.readJson('package.json')
16+
t.equal(scripts.posttest, 'node /path/to/npm run lint')
17+
})
18+
19+
t.test('custom node', async (t) => {
20+
const s = await setup(t, {
21+
ok: true,
22+
package: {
23+
templateOSS: {
24+
npmBin: 'node /path/to/npm',
25+
},
26+
},
27+
})
28+
await s.apply()
29+
const { scripts } = await s.readJson('package.json')
30+
t.equal(scripts.posttest, 'node /path/to/npm run lint')
31+
})
32+
33+
t.test('relative npm bin with workspaces', async (t) => {
34+
const s = await setup(t, {
35+
ok: true,
36+
package: {
37+
templateOSS: {
38+
npmBin: 'cli.js',
39+
},
40+
},
41+
workspaces: { a: '@name/aaaa', b: 'bbb' },
42+
})
43+
await s.apply()
44+
const { scripts } = await s.readJson('package.json')
45+
const { scripts: scriptsA } = await s.readJson(join(s.workspaces.a, 'package.json'))
46+
const { scripts: scriptsB } = await s.readJson(join(s.workspaces.b, 'package.json'))
47+
t.equal(scripts.posttest, 'node cli.js run lint')
48+
t.equal(scriptsA.posttest, 'node ../../cli.js run lint')
49+
t.equal(scriptsB.posttest, 'node ../../cli.js run lint')
50+
})
51+
52+
t.test('npm bin workspaces only with root config', async (t) => {
53+
const s = await setup(t, {
54+
ok: true,
55+
package: {
56+
templateOSS: {
57+
rootRepo: false,
58+
rootModule: false,
59+
npmBin: './cli.js',
60+
},
61+
},
62+
workspaces: { a: '@name/aaaa', b: 'bbb' },
63+
})
64+
await s.apply()
65+
const { scripts } = await s.readJson('package.json')
66+
const { scripts: scriptsA } = await s.readJson(join(s.workspaces.a, 'package.json'))
67+
const { scripts: scriptsB } = await s.readJson(join(s.workspaces.b, 'package.json'))
68+
t.equal(scripts, undefined)
69+
t.equal(scriptsA.posttest, 'node ../../cli.js run lint')
70+
t.equal(scriptsB.posttest, 'node ../../cli.js run lint')
71+
})
72+
73+
t.test('separate workspace configs', async (t) => {
74+
const s = await setup(t, {
75+
ok: true,
76+
package: {
77+
templateOSS: {
78+
rootRepo: false,
79+
rootModule: false,
80+
},
81+
},
82+
workspaces: {
83+
a: {
84+
name: 'a',
85+
templateOSS: {
86+
npmBin: 'bin_a.js',
87+
},
88+
},
89+
b: {
90+
name: 'b',
91+
templateOSS: {
92+
npmBin: 'bin_b.js',
93+
},
94+
},
95+
},
96+
})
97+
await s.apply()
98+
const { scripts } = await s.readJson('package.json')
99+
const { scripts: scriptsA } = await s.readJson(join(s.workspaces.a, 'package.json'))
100+
const { scripts: scriptsB } = await s.readJson(join(s.workspaces.b, 'package.json'))
101+
t.equal(scripts, undefined)
102+
t.equal(scriptsA.posttest, 'node bin_a.js run lint')
103+
t.equal(scriptsB.posttest, 'node bin_b.js run lint')
104+
})

0 commit comments

Comments
 (0)