11cb0ef41Sopenharmony_ci/* globals config, dirname, package, basename, yes, prompt */ 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst fs = require('fs/promises') 41cb0ef41Sopenharmony_ciconst path = require('path') 51cb0ef41Sopenharmony_ciconst validateLicense = require('validate-npm-package-license') 61cb0ef41Sopenharmony_ciconst validateName = require('validate-npm-package-name') 71cb0ef41Sopenharmony_ciconst npa = require('npm-package-arg') 81cb0ef41Sopenharmony_ciconst semver = require('semver') 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci// more popular packages should go here, maybe? 111cb0ef41Sopenharmony_ciconst isTestPkg = (p) => !!p.match(/^(expresso|mocha|tap|coffee-script|coco|streamline)$/) 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciconst invalid = (msg) => Object.assign(new Error(msg), { notValid: true }) 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst readDeps = (test, excluded) => async () => { 161cb0ef41Sopenharmony_ci const dirs = await fs.readdir('node_modules').catch(() => null) 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci if (!dirs) { 191cb0ef41Sopenharmony_ci return 201cb0ef41Sopenharmony_ci } 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci const deps = {} 231cb0ef41Sopenharmony_ci for (const dir of dirs) { 241cb0ef41Sopenharmony_ci if (dir.match(/^\./) || test !== isTestPkg(dir) || excluded[dir]) { 251cb0ef41Sopenharmony_ci continue 261cb0ef41Sopenharmony_ci } 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci const dp = path.join(dirname, 'node_modules', dir, 'package.json') 291cb0ef41Sopenharmony_ci const p = await fs.readFile(dp, 'utf8').then((d) => JSON.parse(d)).catch(() => null) 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci if (!p || !p.version || p?._requiredBy?.some((r) => r === '#USER')) { 321cb0ef41Sopenharmony_ci continue 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci deps[dir] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci return deps 391cb0ef41Sopenharmony_ci} 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ciconst getConfig = (key) => { 421cb0ef41Sopenharmony_ci // dots take precedence over dashes 431cb0ef41Sopenharmony_ci const def = config?.defaults?.[`init.${key}`] 441cb0ef41Sopenharmony_ci const val = config.get(`init.${key}`) 451cb0ef41Sopenharmony_ci return (val !== def && val) ? val : config.get(`init-${key.replace(/\./g, '-')}`) 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ciconst getName = () => { 491cb0ef41Sopenharmony_ci const rawName = package.name || basename 501cb0ef41Sopenharmony_ci let name = rawName 511cb0ef41Sopenharmony_ci .replace(/^node-|[.-]js$/g, '') 521cb0ef41Sopenharmony_ci .replace(/\s+/g, ' ') 531cb0ef41Sopenharmony_ci .replace(/ /g, '-') 541cb0ef41Sopenharmony_ci .toLowerCase() 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci let spec 571cb0ef41Sopenharmony_ci try { 581cb0ef41Sopenharmony_ci spec = npa(name) 591cb0ef41Sopenharmony_ci } catch { 601cb0ef41Sopenharmony_ci spec = {} 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci let scope = config.get('scope') 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci if (scope) { 661cb0ef41Sopenharmony_ci if (scope.charAt(0) !== '@') { 671cb0ef41Sopenharmony_ci scope = '@' + scope 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci if (spec.scope) { 701cb0ef41Sopenharmony_ci name = scope + '/' + spec.name.split('/')[1] 711cb0ef41Sopenharmony_ci } else { 721cb0ef41Sopenharmony_ci name = scope + '/' + name 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci return name 771cb0ef41Sopenharmony_ci} 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ciconst name = getName() 801cb0ef41Sopenharmony_ciexports.name = yes ? name : prompt('package name', name, (data) => { 811cb0ef41Sopenharmony_ci const its = validateName(data) 821cb0ef41Sopenharmony_ci if (its.validForNewPackages) { 831cb0ef41Sopenharmony_ci return data 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci const errors = (its.errors || []).concat(its.warnings || []) 861cb0ef41Sopenharmony_ci return invalid(`Sorry, ${errors.join(' and ')}.`) 871cb0ef41Sopenharmony_ci}) 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ciconst version = package.version || getConfig('version') || '1.0.0' 901cb0ef41Sopenharmony_ciexports.version = yes ? version : prompt('version', version, (v) => { 911cb0ef41Sopenharmony_ci if (semver.valid(v)) { 921cb0ef41Sopenharmony_ci return v 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci return invalid(`Invalid version: "${v}"`) 951cb0ef41Sopenharmony_ci}) 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ciif (!package.description) { 981cb0ef41Sopenharmony_ci exports.description = yes ? '' : prompt('description') 991cb0ef41Sopenharmony_ci} 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ciif (!package.main) { 1021cb0ef41Sopenharmony_ci exports.main = async () => { 1031cb0ef41Sopenharmony_ci const files = await fs.readdir(dirname) 1041cb0ef41Sopenharmony_ci .then(list => list.filter((f) => f.match(/\.js$/))) 1051cb0ef41Sopenharmony_ci .catch(() => []) 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci let index 1081cb0ef41Sopenharmony_ci if (files.includes('index.js')) { 1091cb0ef41Sopenharmony_ci index = 'index.js' 1101cb0ef41Sopenharmony_ci } else if (files.includes('main.js')) { 1111cb0ef41Sopenharmony_ci index = 'main.js' 1121cb0ef41Sopenharmony_ci } else if (files.includes(basename + '.js')) { 1131cb0ef41Sopenharmony_ci index = basename + '.js' 1141cb0ef41Sopenharmony_ci } else { 1151cb0ef41Sopenharmony_ci index = files[0] || 'index.js' 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci return yes ? index : prompt('entry point', index) 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ciif (!package.bin) { 1231cb0ef41Sopenharmony_ci exports.bin = async () => { 1241cb0ef41Sopenharmony_ci try { 1251cb0ef41Sopenharmony_ci const d = await fs.readdir(path.resolve(dirname, 'bin')) 1261cb0ef41Sopenharmony_ci // just take the first js file we find there, or nada 1271cb0ef41Sopenharmony_ci let r = d.find(f => f.match(/\.js$/)) 1281cb0ef41Sopenharmony_ci if (r) { 1291cb0ef41Sopenharmony_ci r = `bin/${r}` 1301cb0ef41Sopenharmony_ci } 1311cb0ef41Sopenharmony_ci return r 1321cb0ef41Sopenharmony_ci } catch { 1331cb0ef41Sopenharmony_ci // no bins 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ciexports.directories = async () => { 1391cb0ef41Sopenharmony_ci const dirs = await fs.readdir(dirname) 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci const res = dirs.reduce((acc, d) => { 1421cb0ef41Sopenharmony_ci if (/^examples?$/.test(d)) { 1431cb0ef41Sopenharmony_ci acc.example = d 1441cb0ef41Sopenharmony_ci } else if (/^tests?$/.test(d)) { 1451cb0ef41Sopenharmony_ci acc.test = d 1461cb0ef41Sopenharmony_ci } else if (/^docs?$/.test(d)) { 1471cb0ef41Sopenharmony_ci acc.doc = d 1481cb0ef41Sopenharmony_ci } else if (d === 'man') { 1491cb0ef41Sopenharmony_ci acc.man = d 1501cb0ef41Sopenharmony_ci } else if (d === 'lib') { 1511cb0ef41Sopenharmony_ci acc.lib = d 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci return acc 1551cb0ef41Sopenharmony_ci }, {}) 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci return Object.keys(res).length === 0 ? undefined : res 1581cb0ef41Sopenharmony_ci} 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ciif (!package.dependencies) { 1611cb0ef41Sopenharmony_ci exports.dependencies = readDeps(false, package.devDependencies || {}) 1621cb0ef41Sopenharmony_ci} 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ciif (!package.devDependencies) { 1651cb0ef41Sopenharmony_ci exports.devDependencies = readDeps(true, package.dependencies || {}) 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci// MUST have a test script! 1691cb0ef41Sopenharmony_ciif (!package.scripts) { 1701cb0ef41Sopenharmony_ci const scripts = package.scripts || {} 1711cb0ef41Sopenharmony_ci const notest = 'echo "Error: no test specified" && exit 1' 1721cb0ef41Sopenharmony_ci exports.scripts = async () => { 1731cb0ef41Sopenharmony_ci const d = await fs.readdir(path.join(dirname, 'node_modules')).catch(() => []) 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci // check to see what framework is in use, if any 1761cb0ef41Sopenharmony_ci let command 1771cb0ef41Sopenharmony_ci if (!scripts.test || scripts.test === notest) { 1781cb0ef41Sopenharmony_ci const commands = { 1791cb0ef41Sopenharmony_ci tap: 'tap test/*.js', 1801cb0ef41Sopenharmony_ci expresso: 'expresso test', 1811cb0ef41Sopenharmony_ci mocha: 'mocha', 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci for (const [k, v] of Object.entries(commands)) { 1841cb0ef41Sopenharmony_ci if (d.includes(k)) { 1851cb0ef41Sopenharmony_ci command = v 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci const promptArgs = ['test command', (t) => t || notest] 1911cb0ef41Sopenharmony_ci if (command) { 1921cb0ef41Sopenharmony_ci promptArgs.splice(1, 0, command) 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci scripts.test = yes ? command || notest : prompt(...promptArgs) 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci return scripts 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ciif (!package.repository) { 2011cb0ef41Sopenharmony_ci exports.repository = async () => { 2021cb0ef41Sopenharmony_ci const gconf = await fs.readFile('.git/config', 'utf8').catch(() => '') 2031cb0ef41Sopenharmony_ci const lines = gconf.split(/\r?\n/) 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci let url 2061cb0ef41Sopenharmony_ci const i = lines.indexOf('[remote "origin"]') 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci if (i !== -1) { 2091cb0ef41Sopenharmony_ci url = gconf[i + 1] 2101cb0ef41Sopenharmony_ci if (!url.match(/^\s*url =/)) { 2111cb0ef41Sopenharmony_ci url = gconf[i + 2] 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci if (!url.match(/^\s*url =/)) { 2141cb0ef41Sopenharmony_ci url = null 2151cb0ef41Sopenharmony_ci } else { 2161cb0ef41Sopenharmony_ci url = url.replace(/^\s*url = /, '') 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci if (url && url.match(/^git@github.com:/)) { 2211cb0ef41Sopenharmony_ci url = url.replace(/^git@github.com:/, 'https://github.com/') 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci return yes ? url || '' : prompt('git repository', url || undefined) 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci} 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ciif (!package.keywords) { 2291cb0ef41Sopenharmony_ci exports.keywords = yes ? '' : prompt('keywords', (data) => { 2301cb0ef41Sopenharmony_ci if (!data) { 2311cb0ef41Sopenharmony_ci return 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci if (Array.isArray(data)) { 2341cb0ef41Sopenharmony_ci data = data.join(' ') 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci if (typeof data !== 'string') { 2371cb0ef41Sopenharmony_ci return data 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci return data.split(/[\s,]+/) 2401cb0ef41Sopenharmony_ci }) 2411cb0ef41Sopenharmony_ci} 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ciif (!package.author) { 2441cb0ef41Sopenharmony_ci const authorName = getConfig('author.name') 2451cb0ef41Sopenharmony_ci exports.author = authorName 2461cb0ef41Sopenharmony_ci ? { 2471cb0ef41Sopenharmony_ci name: authorName, 2481cb0ef41Sopenharmony_ci email: getConfig('author.email'), 2491cb0ef41Sopenharmony_ci url: getConfig('author.url'), 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci : yes ? '' : prompt('author') 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciconst license = package.license || getConfig('license') || 'ISC' 2551cb0ef41Sopenharmony_ciexports.license = yes ? license : prompt('license', license, (data) => { 2561cb0ef41Sopenharmony_ci const its = validateLicense(data) 2571cb0ef41Sopenharmony_ci if (its.validForNewPackages) { 2581cb0ef41Sopenharmony_ci return data 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci const errors = (its.errors || []).concat(its.warnings || []) 2611cb0ef41Sopenharmony_ci return invalid(`Sorry, ${errors.join(' and ')}.`) 2621cb0ef41Sopenharmony_ci}) 263