|
/* globals config, dirname, package, basename, yes, prompt */ |
|
|
|
const fs = require('fs/promises') |
|
const path = require('path') |
|
|
|
// more popular packages should go here, maybe? |
|
const testPkgs = [ |
|
'coco', |
|
'coffee-script', |
|
'expresso', |
|
'jasmine', |
|
'jest', |
|
'mocha', |
|
'streamline', |
|
'tap', |
|
] |
|
const isTestPkg = p => testPkgs.includes(p) |
|
|
|
const invalid = (msg) => Object.assign(new Error(msg), { notValid: true }) |
|
|
|
const readDeps = (test, excluded) => async () => { |
|
const dirs = await fs.readdir('node_modules').catch(() => null) |
|
|
|
if (!dirs) { |
|
return |
|
} |
|
|
|
const deps = {} |
|
for (const dir of dirs) { |
|
if (dir.match(/^\./) || test !== isTestPkg(dir) || excluded[dir]) { |
|
continue |
|
} |
|
|
|
const dp = path.join(dirname, 'node_modules', dir, 'package.json') |
|
const p = await fs.readFile(dp, 'utf8').then((d) => JSON.parse(d)).catch(() => null) |
|
|
|
if (!p || !p.version || p?._requiredBy?.some((r) => r === '#USER')) { |
|
continue |
|
} |
|
|
|
deps[dir] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version |
|
} |
|
|
|
return deps |
|
} |
|
|
|
const getConfig = (key) => { |
|
// dots take precedence over dashes |
|
const def = config?.defaults?.[`init.${key}`] |
|
const val = config.get(`init.${key}`) |
|
return (val !== def && val) ? val : config.get(`init-${key.replace(/\./g, '-')}`) |
|
} |
|
|
|
const getName = () => { |
|
const rawName = package.name || basename |
|
let name = rawName |
|
.replace(/^node-|[.-]js$/g, '') |
|
.replace(/\s+/g, ' ') |
|
.replace(/ /g, '-') |
|
.toLowerCase() |
|
|
|
return name |
|
} |
|
|
|
const name = getName() |
|
exports.name = yes ? name : prompt('package name', name, (data) => { |
|
return data |
|
}) |
|
|
|
const version = package.version || getConfig('version') || '1.0.0' |
|
exports.version = yes ? version : prompt('version', version, (v) => { |
|
return v |
|
}) |
|
|
|
if (!package.description) { |
|
exports.description = yes ? '' : prompt('description') |
|
} |
|
|
|
if (!package.main) { |
|
exports.main = async () => { |
|
const files = await fs.readdir(dirname) |
|
.then(list => list.filter((f) => f.match(/\.js$/))) |
|
.catch(() => []) |
|
|
|
let index |
|
if (files.includes('index.js')) { |
|
index = 'index.js' |
|
} else if (files.includes('main.js')) { |
|
index = 'main.js' |
|
} else if (files.includes(basename + '.js')) { |
|
index = basename + '.js' |
|
} else { |
|
index = files[0] || 'index.js' |
|
} |
|
|
|
return yes ? index : prompt('entry point', index) |
|
} |
|
} |
|
|
|
if (!package.bin) { |
|
exports.bin = async () => { |
|
try { |
|
const d = await fs.readdir(path.resolve(dirname, 'bin')) |
|
// just take the first js file we find there, or nada |
|
let r = d.find(f => f.match(/\.js$/)) |
|
if (r) { |
|
r = `bin/${r}` |
|
} |
|
return r |
|
} catch { |
|
// no bins |
|
} |
|
} |
|
} |
|
|
|
exports.directories = async () => { |
|
const dirs = await fs.readdir(dirname) |
|
|
|
const res = dirs.reduce((acc, d) => { |
|
if (/^examples?$/.test(d)) { |
|
acc.example = d |
|
} else if (/^tests?$/.test(d)) { |
|
acc.test = d |
|
} else if (/^docs?$/.test(d)) { |
|
acc.doc = d |
|
} else if (d === 'man') { |
|
acc.man = d |
|
} else if (d === 'lib') { |
|
acc.lib = d |
|
} |
|
|
|
return acc |
|
}, {}) |
|
|
|
return Object.keys(res).length === 0 ? undefined : res |
|
} |
|
|
|
if (!package.dependencies) { |
|
exports.dependencies = readDeps(false, package.devDependencies || {}) |
|
} |
|
|
|
if (!package.devDependencies) { |
|
exports.devDependencies = readDeps(true, package.dependencies || {}) |
|
} |
|
|
|
// MUST have a test script! |
|
if (!package.scripts) { |
|
const scripts = package.scripts || {} |
|
const notest = 'echo "Error: no test specified" && exit 1' |
|
exports.scripts = async () => { |
|
const d = await fs.readdir(path.join(dirname, 'node_modules')).catch(() => []) |
|
|
|
// check to see what framework is in use, if any |
|
let command |
|
if (!scripts.test || scripts.test === notest) { |
|
const commands = { |
|
tap: 'tap test/*.js', |
|
expresso: 'expresso test', |
|
mocha: 'mocha', |
|
} |
|
for (const [k, v] of Object.entries(commands)) { |
|
if (d.includes(k)) { |
|
command = v |
|
} |
|
} |
|
} |
|
|
|
const promptArgs = ['test command', (t) => t || notest] |
|
if (command) { |
|
promptArgs.splice(1, 0, command) |
|
} |
|
scripts.test = yes ? command || notest : prompt(...promptArgs) |
|
|
|
return scripts |
|
} |
|
} |
|
|
|
if (!package.repository) { |
|
exports.repository = async () => { |
|
const gitConfigPath = path.resolve(dirname, '.git', 'config') |
|
const gconf = await fs.readFile(gitConfigPath, 'utf8').catch(() => '') |
|
const lines = gconf.split(/\r?\n/) |
|
|
|
let url |
|
const i = lines.indexOf('[remote "origin"]') |
|
|
|
if (i !== -1) { |
|
url = lines[i + 1] |
|
if (!url.match(/^\s*url =/)) { |
|
url = lines[i + 2] |
|
} |
|
if (!url.match(/^\s*url =/)) { |
|
url = null |
|
} else { |
|
url = url.replace(/^\s*url = /, '') |
|
} |
|
} |
|
|
|
if (url && url.match(/^git@github.com:/)) { |
|
url = url.replace(/^git@github.com:/, 'https://github.com/') |
|
} |
|
|
|
return yes ? url || '' : prompt('git repository', url || undefined) |
|
} |
|
} |
|
|
|
if (!package.keywords) { |
|
exports.keywords = yes ? '' : prompt('keywords', (data) => { |
|
if (!data) { |
|
return |
|
} |
|
if (Array.isArray(data)) { |
|
data = data.join(' ') |
|
} |
|
if (typeof data !== 'string') { |
|
return data |
|
} |
|
return data.split(/[\s,]+/) |
|
}) |
|
} |
|
|
|
if (!package.author) { |
|
const authorName = getConfig('author.name') |
|
exports.author = authorName |
|
? { |
|
name: authorName, |
|
email: getConfig('author.email'), |
|
url: getConfig('author.url'), |
|
} |
|
: yes ? '' : prompt('author') |
|
} |
|
|
|
const license = package.license || getConfig('license') || 'ISC' |
|
exports.license = yes ? license : prompt('license', license, (data) => { |
|
return data |
|
}) |
|
|
|
// Only include private field if it already exists or if explicitly set in config |
|
const configPrivate = getConfig('private') |
|
if (package.private !== undefined || configPrivate !== undefined) { |
|
if (package.private !== undefined) { |
|
exports.private = package.private |
|
} else if (!config.isDefault || !config.isDefault('init-private')) { |
|
exports.private = configPrivate |
|
} |
|
} |