Skip to content

Commit 4b15eeb

Browse files
committed
some refactors and added update and source package options
1 parent bc4b13e commit 4b15eeb

7 files changed

Lines changed: 331 additions & 285 deletions

File tree

bin/create-package-json

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ program
1313
.arguments('<directory>')
1414
.action((dir) => directory = dir)
1515
.option('--ignore-existing', 'Ignore existing package.json')
16+
.option('--existing-package [path]', 'Provide a path to an existing package.json to start with')
17+
.option('--update-deps', 'Update deps which to their latest versions')
1618
.option('--no-prompt', 'Skip prompts and just use input options')
19+
.option('--extended', 'Show extended option prompts (ex. browser, engines, etc)')
1720
.option('--spacer [json spacer]', 'Format character for package json', 2)
1821
.option('--name [name]', 'The package name')
1922
.option('--scope [scope]', 'The package scope')
@@ -27,19 +30,31 @@ program
2730
.option('--private', 'This is a private package')
2831
.option('--dependencies [dependencies]', 'Package dependencies')
2932
.option('--dev-dependencies [dependencies]', 'Package dev dependencies')
33+
// .option('--peer-dependencies [dependencies]', 'Package peer dependencies')
3034
.option('--scripts [scripts]', 'Package scripts')
3135
.parse(process.argv)
3236

3337
// Process scripts as json
3438
if (program.scripts) {
3539
program.scripts = JSON.parse(program.scripts)
3640
}
41+
if (program.dependencies) {
42+
program.dependencies = arrayFromList(program.dependencies)
43+
}
44+
if (program.devDependencies) {
45+
program.devDependencies = arrayFromList(program.devDependencies)
46+
}
47+
// if (program.peerDependencies) {
48+
// program.peerDependencies = arrayFromList(program.peerDependencies)
49+
// }
3750

3851
// Run the process
3952
createPackageJson({
4053
directory: directory,
4154
ignoreExisting: program.ignoreExisting,
55+
existingPackage: program.existingPackage,
4256
noPrompt: program.noPrompt,
57+
extended: program.extended,
4358
spacer: program.spacer,
4459
// check if string because there is a .name getter function, same with description
4560
name: typeof program.name === 'string' ? program.name : undefined,
@@ -53,6 +68,8 @@ createPackageJson({
5368
main: program.main,
5469
private: program.private,
5570
scripts: program.scripts,
56-
dependencies: arrayFromList(program.dependencies),
57-
devDependencies: arrayFromList(program.devDependencies)
71+
dependencies: program.dependencies,
72+
devDependencies: program.devDependencies,
73+
updateDeps: program.updateDeps
74+
// peerDependencies: program.peerDependencies
5875
})

index.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ const scopeAndName = require('./lib/scope-and-name')
1212
const gitRemote = require('./lib/git-remote')
1313

1414
// @TODO https://docs.npmjs.com/files/package.json
15-
// man
1615
// bin
1716
// files
1817
// browser
@@ -40,27 +39,34 @@ module.exports = async function createPackageJson (input = {}) {
4039
spacer: 2,
4140
directory: cwd,
4241
pkgPath: path.join(input.directory || cwd, 'package.json'),
42+
updateDeps: true,
4343
ignoreExisting: false,
4444
noPrompt: false,
45-
silent: false
45+
silent: false,
46+
extended: false
4647
})
4748

4849
// Read existing package.json
4950
const pkg = await readPackageJson(options)
5051

5152
// Build up the package field options and merge it all together
52-
const opts = await buildPackageOptions(options, pkg)
53+
let opts = await buildPackageOptions(options, pkg)
54+
55+
opts = await prompt(opts, options)
56+
57+
// Merge peer deps into dev deps
58+
// opts.devDependencies = opts.devDependencies.concat(opts.peerDependencies || [])
5359

5460
// Format the json and write it out
55-
return write(await prompt(opts, options), format(opts, pkg))
61+
return write(opts, format(opts, pkg))
5662
}
5763

5864
module.exports.readPackageJson = readPackageJson
5965
async function readPackageJson (opts = {}) {
6066
let pkg = {}
6167
if (opts.ignoreExisting !== true) {
6268
try {
63-
pkg = await fs.readJSON(opts.pkgPath)
69+
pkg = await fs.readJSON(opts.existingPackage || opts.pkgPath)
6470
} catch (e) {
6571
// ignore if missing or unreadable
6672
}
@@ -82,8 +88,12 @@ async function buildPackageOptions (options = {}, pkg = {}) {
8288
opts.license = options.license || pkg.license || 'ISC'
8389
opts.main = options.main || pkg.main || 'index.js'
8490
opts.private = defined(options.private, pkg.private)
85-
opts.dependencies = mapDepToVersionString(arrayOrUndefined(options.dependencies) || pkg.dependencies || [])
86-
opts.devDependencies = mapDepToVersionString(arrayOrUndefined(options.devDependencies) || pkg.devDependencies || [])
91+
opts.dependencies = mapDepToVersionString(arrayOrUndefined(options.dependencies) || pkg.dependencies || [], !opts.updateDeps)
92+
opts.devDependencies = mapDepToVersionString(arrayOrUndefined(options.devDependencies) || pkg.devDependencies || [], !opts.updateDeps)
93+
// opts.peerDependencies = mapDepToVersionString(arrayOrUndefined(options.peerDependencies) || pkg.peerDependencies || [])
94+
95+
// Extended options
96+
opts.man = options.man || pkg.man
8797

8898
// Merge together scripts from opts and package.json
8999
opts.scripts = Object.assign({}, options.scripts || {}, pkg.scripts || {})
@@ -115,6 +125,13 @@ function format (opts, pkg = {}) {
115125
if (opts.private === true) {
116126
pkg.private = true
117127
}
128+
if (opts.man && opts.man.length) {
129+
pkg.man = Array.isArray(opts.man) && !opts.man[1] ? opts.man[0] : opts.man
130+
}
131+
// @TODO ensure they are formatted correctly?
132+
// if (opts.peerDependencies) {
133+
// pkg.peerDependencies = opts.peerDependencies
134+
// }
118135
return pkg
119136
}
120137

lib/array-from-list.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict'
2-
// vim: set ft=javascript:ts=2:sw=2
2+
// vim: set ft=javascript:ts=2:sw=2:
33

44
module.exports = function arrayFromList (list) {
55
let arr = list || []

lib/map-dep-to-version-string.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22
// vim: set ft=javascript ts=2 sw=2:
33

4-
module.exports = function mapDepToVersionString (deps) {
5-
return Array.isArray(deps) ? deps : Object.keys(deps).map((name) => `${name}@${deps[name]}`)
4+
module.exports = function mapDepToVersionString (deps, withVersion) {
5+
return Array.isArray(deps) ? deps : Object.keys(deps).map((name) => withVersion ? `${name}@${deps[name]}` : name)
66
}

lib/prompts.js

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use strict'
22
// vim: set ft=javascript ts=2 sw=2:
3+
const path = require('path')
34
const inquirer = require('inquirer')
45
const validatePackageName = require('validate-npm-package-name')
6+
const realizePackageSpecifier = require('realize-package-specifier')
57
const arrayFromList = require('./array-from-list')
68
const arrayOrUndefined = require('./array-or-undefined')
79

@@ -28,7 +30,8 @@ module.exports = async function prompt (opts = {}, options = {}) {
2830
}, {
2931
name: 'description',
3032
message: 'Description:',
31-
default: opts.description,
33+
// This is because inquirer treats an empty string as truthy and shows ()
34+
default: opts.description ? opts.description : undefined,
3235
when: !options.description
3336
}, {
3437
name: 'author',
@@ -42,34 +45,46 @@ module.exports = async function prompt (opts = {}, options = {}) {
4245
when: !options.repository
4346
}, {
4447
name: 'keywords',
45-
message: 'Keywords (ex: blockchain, ninja):',
48+
message: 'Keywords [ex: blockchain, ninja]:',
4649
default: arrayOrUndefined(opts.keywords),
4750
when: !options.keywords,
4851
filter: arrayFromList
4952
}, {
5053
name: 'license',
51-
message: 'License (ex: MIT, unlicensed):',
54+
message: 'License [ex: MIT, unlicensed]:',
5255
default: opts.license,
5356
when: !options.license
5457
}, {
5558
name: 'main',
56-
message: 'Entry point (main):',
59+
message: 'Entry point:',
5760
default: opts.main,
5861
when: !options.main
5962
}, {
6063
name: 'dependencies',
61-
message: 'Dependencies (ex: express, react):',
64+
message: 'Dependencies [ex: express, react]:',
6265
default: arrayOrUndefined(opts.dependencies),
6366
when: !options.dependencies,
6467
filter: arrayFromList,
6568
validate: validatePackageNames
6669
}, {
6770
name: 'devDependencies',
68-
message: 'Dev Dependencies (ex: mocha, webpack):',
71+
message: 'Dev Dependencies [ex: mocha, webpack]:',
6972
default: arrayOrUndefined(opts.devDependencies),
7073
when: !options.devDependencies,
7174
filter: arrayFromList,
7275
validate: validatePackageNames
76+
}, {
77+
name: 'private',
78+
type: 'confirm',
79+
message: 'Is this package private?',
80+
default: !!opts.private,
81+
when: opts.extended && typeof options.private === 'undefined'
82+
}, {
83+
name: 'man',
84+
message: 'Man Pages:',
85+
default: opts.man,
86+
when: opts.extended && !options.man,
87+
filter: arrayFromList
7388
}])
7489

7590
// Get custom scripts
@@ -89,28 +104,28 @@ async function promptForScripts (opts = {}, options = {}) {
89104
when: !options.scripts || !options.scripts.test
90105
}, {
91106
name: 'prepare',
92-
message: 'Prepare script (run before publish and on local install):',
107+
message: 'Prepare script [run before publish and on local install]:',
93108
default: s.prepare,
94-
when: !options.scripts || !options.scripts.prepare
109+
when: opts.extended && (!options.scripts || !options.scripts.prepare)
95110
}, {
96111
name: 'prepublushOnly',
97-
message: 'Pre publush script (run only before publish):',
112+
message: 'Pre publush script [run only before publish]:',
98113
default: s.prepublushOnly || 'npm t',
99114
when: !options.scripts || !options.scripts.prepublushOnly
100115
}, {
101116
name: 'postpublish',
102117
message: 'Post publish script:',
103118
default: s.postpublish,
104-
when: !options.scripts || !options.scripts.postpublish
119+
when: opts.extended && (!options.scripts || !options.scripts.postpublish)
105120
}, {
106121
name: 'preversion',
107122
message: 'Pre version script:',
108-
default: s.postpublish,
109-
when: !options.scripts || !options.scripts.postpublish
123+
default: s.preversion,
124+
when: opts.extended && (!options.scripts || !options.scripts.preversion)
110125
}])
111126

112127
// Merge scripts and add any customs
113-
const scripts = await promptForCustomScript(Object.assign(s, commonScripts))
128+
const scripts = await promptForCustomScript(opts, Object.assign(s, commonScripts))
114129

115130
// Remove empty scripts
116131
return Object.keys(scripts).reduce((s, key) => {
@@ -121,7 +136,11 @@ async function promptForScripts (opts = {}, options = {}) {
121136
}, {})
122137
}
123138

124-
async function promptForCustomScript (scripts = {}) {
139+
async function promptForCustomScript (opts = {}, scripts = {}) {
140+
if (!opts.extended) {
141+
return scripts
142+
}
143+
125144
const {another} = await inquirer.prompt([{
126145
name: 'another',
127146
message: 'Add another script?',
@@ -143,13 +162,55 @@ async function promptForCustomScript (scripts = {}) {
143162

144163
scripts[script.name] = script.content
145164

146-
return promptForCustomScript(scripts)
165+
return promptForCustomScript(opts, scripts)
166+
}
167+
168+
async function validatePackageNames (input) {
169+
if (!input) {
170+
return true
171+
}
172+
173+
let valid = true
174+
for (let i = 0; i < input.length && valid === true; i++) {
175+
let pkg
176+
try {
177+
pkg = await realizePkgSpec(input[i])
178+
} catch (e) {
179+
return e
180+
}
181+
182+
switch (pkg.type) {
183+
// Directory checkes for package.json and
184+
// hosted means it looks like a remote repo or tarball
185+
case 'directory':
186+
case 'hosted':
187+
return true
188+
case 'local':
189+
// check for something that looks like a path
190+
// because any random string is marked as local
191+
if (pkg.raw.includes('.') || pkg.raw.includes(path.sep)) {
192+
continue
193+
}
194+
}
195+
196+
// Manual check because the validate package just says "name cannot be null"
197+
if (!pkg.name) {
198+
return new Error('Invalid package name: ' + pkg.raw)
199+
}
200+
201+
let v = validatePackageName(pkg.name)
202+
valid = v.validForNewPackages || v.validForOldPackages ? true : ((v.errors && v.errors[0]) || `Invalid package name: ${input[i]}`)
203+
}
204+
return valid
147205
}
148206

149-
function validatePackageNames (input) {
150-
const error = input.reduce((err, name) => {
151-
let v = validatePackageName(name)
152-
return err || (v.validForNewPackages || v.validForOldPackages ? true : ((v.errors && v.errors[0]) || `Invalid package name: ${name}`))
153-
}, null)
154-
return error || true
207+
function realizePkgSpec (name) {
208+
return new Promise((resolve, reject) => {
209+
realizePackageSpecifier(name, (err, pkg) => {
210+
if (err) {
211+
return reject(err)
212+
}
213+
resolve(pkg)
214+
})
215+
})
155216
}

0 commit comments

Comments
 (0)