/* eslint-disable no-console */ const path = require('path') const fs = require('fs') const fse = require('fs-extra') const glob = require('glob') const yaml = require('js-yaml') const chalk = require('chalk') const handlebars = require('handlebars') const Mustache = require('mustache') const { version } = require('../lerna.json') const repoPath = process.cwd() const config = { repoPath, defaults: readConfigFile('defaults.yaml'), descriptions: readConfigFile('descriptions.yaml'), keywords: readConfigFile('keywords.yaml'), badges: readConfigFile('badges.yaml'), scripts: readConfigFile('scripts.yaml'), changelog: readConfigFile('changelog.yaml'), changetypes: ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'], dependencies: readConfigFile('dependencies.yaml', { version }), exceptions: readConfigFile('exceptions.yaml'), templates: { pkg: readTemplateFile('package.dflt.json'), rollup: readTemplateFile('rollup.config.dflt.js'), changelog: readTemplateFile('changelog.dflt.md'), readme: readTemplateFile('readme.dflt.md') } } const packages = glob.sync('*', { cwd: path.join(config.repoPath, 'packages') }) validate(packages, config) reconfigure(packages, config) process.exit() /** * Reads a template file */ function readTemplateFile(file) { return fs.readFileSync(path.join(repoPath, 'config', 'templates', file), 'utf-8') } /** * Reads a pattern example file */ function readExampleFile(file, subdir = false) { return fs.readFileSync( subdir ? path.join( repoPath, 'packages', 'create-freesewing-pattern', 'template', 'default', 'example', file ) : path.join( repoPath, 'packages', 'create-freesewing-pattern', 'template', 'default', 'example', subdir, file ), 'utf-8' ) } /** * Reads a YAML config file, with Mustache replacements if needed */ function readConfigFile(file, replace = false) { if (replace) return yaml.safeLoad( Mustache.render(fs.readFileSync(path.join(repoPath, 'config', file), 'utf-8'), replace) ) return yaml.safeLoad(fs.readFileSync(path.join(repoPath, 'config', file), 'utf-8')) } /** * Reads info.md from the package directory * Returns its contents if it exists, or an empty string if not */ function readInfoFile(pkg) { let markup = '' try { markup = fs.readFileSync(path.join(repoPath, 'packages', pkg, 'info.md'), 'utf-8') } catch { return '' } return markup } /** * Figure out what sort of package this is. * Returns a string, one of: * - pattern * - plugin * - other */ function packageType(pkg, config) { if (pkg.substring(0, 7) === 'plugin-') return 'plugin' if (config.descriptions[pkg].substring(0, 21) === 'A FreeSewing pattern ') return 'pattern' return 'other' } /** * Returns an array of keywords for a package */ function keywords(pkg, config, type) { if (typeof config.keywords[pkg] !== 'undefined') return config.keywords[pkg] if (typeof config.keywords[type] !== 'undefined') return config.keywords[type] else { console.log( chalk.redBright.bold('Problem:'), chalk.redBright(`No keywords for package ${pkg} which is of type ${type}`) ) process.exit() } } /** * Returns an plain object of scripts for a package */ function scripts(pkg, config, type) { let runScripts = {} for (let key of Object.keys(config.scripts._)) { runScripts[key] = Mustache.render(config.scripts._[key], { name: pkg }) } if (typeof config.scripts._types[type] !== 'undefined') { for (let key of Object.keys(config.scripts._types[type])) { runScripts[key] = Mustache.render(config.scripts._types[type][key], { name: pkg }) } } if (typeof config.scripts[pkg] !== 'undefined') { for (let key of Object.keys(config.scripts[pkg])) { if (config.scripts[pkg][key] === '!') delete runScripts[key] else runScripts[key] = Mustache.render(config.scripts[pkg][key], { name: pkg }) } } return runScripts } /** * Returns an plain object with the of dependencies for a package * section is the key in the dependencies.yaml fine, one of: * * - _ (for dependencies) * - dev (for devDependencies) * - peer (for peerDependencies) * */ function deps(section, pkg, config, type) { let dependencies = {} if ( typeof config.dependencies._types[type] !== 'undefined' && typeof config.dependencies._types[type][section] !== 'undefined' ) dependencies = config.dependencies._types[type][section] if (typeof config.dependencies[pkg] === 'undefined') return dependencies if (typeof config.dependencies[pkg][section] !== 'undefined') return { ...dependencies, ...config.dependencies[pkg][section] } return dependencies } /** * These merely call deps() for the relevant dependency section */ function dependencies(pkg, config, type) { return deps('_', pkg, config, type) } function devDependencies(pkg, config, type) { return deps('dev', pkg, config, type) } function peerDependencies(pkg, config, type) { return deps('peer', pkg, config, type) } /** * Creates a package.json file for a package */ function packageConfig(pkg, config) { let type = packageType(pkg, config) let pkgConf = {} // Let's keep these at the top pkgConf.name = fullName(pkg, config) pkgConf.version = version pkgConf.description = config.descriptions[pkg] pkgConf = { ...pkgConf, ...JSON.parse(Mustache.render(config.templates.pkg, { name: pkg })) } pkgConf.keywords = pkgConf.keywords.concat(keywords(pkg, config, type)) pkgConf.scripts = scripts(pkg, config, type) pkgConf.dependencies = dependencies(pkg, config, type) pkgConf.devDependencies = devDependencies(pkg, config, type) pkgConf.peerDependencies = peerDependencies(pkg, config, type) if (typeof config.exceptions.packageJson[pkg] !== 'undefined') { pkgConf = { ...pkgConf, ...config.exceptions.packageJson[pkg] } for (let key of Object.keys(config.exceptions.packageJson[pkg])) { if (config.exceptions.packageJson[pkg][key] === '!') delete pkgConf[key] } } return pkgConf } /** * Returns an string with the markup for badges in the readme file */ function badges(pkg, config) { let markup = '' for (let group of ['_all', '_social']) { markup += "
" for (let key of Object.keys(config.badges[group])) { markup += formatBadge(config.badges[group][key], pkg, fullName(pkg, config)) } markup += '
' } return markup } /** * Formats a badge for a readme file */ function formatBadge(badge, name, fullname) { return `