tibi-docs/.yarn/unplugged/metalsmith-npm-2.5.1-131e5add51/node_modules/metalsmith/bin/_metalsmith
2022-11-02 06:40:25 +00:00

188 lines
4.3 KiB
JavaScript
Executable File

#!/usr/bin/env node
/* eslint-disable no-console */
const exists = require('fs').existsSync
const Metalsmith = require('..')
const program = require('commander')
const { resolve, isAbsolute, dirname } = require('path')
const { isString, isObject } = require('../lib/helpers')
const color = {
error: '\x1b[31m',
warn: '\x1b[33m',
info: '\x1b[36m',
success: '\x1b[32m',
log: '\x1b[0m'
}
/**
* Usage.
*/
program
.version(require('../package.json').version)
.option('-c, --config <path>', 'configuration file location', 'metalsmith.json')
/**
* Examples.
*/
program.on('--help', function () {
console.log(' Examples:')
console.log()
console.log(' # build from metalsmith.json:')
console.log(' $ metalsmith')
console.log()
console.log(' # build from lib/config.json:')
console.log(' $ metalsmith --config lib/config.json')
console.log()
})
/**
* Parse.
*/
program.parse(process.argv)
/**
* Config.
*/
const dir = process.cwd()
const config = program.config
const path = isAbsolute(config) ? config : resolve(dir, config)
// Important addition of 2.5.x. Given local plugins with a relative path are written with __dirname in mind,
// having a config-relative dir path makes sure the CLI runs properly
// when the command is executed from a subfolder or outside of the ms directory
const confRelativeDir = dirname(path)
if (!exists(path)) fatal(`could not find a ${config} configuration file.`)
let json
try {
// requiring json is incompatible with ESM, however given the metalsmith CLI is not meant to be "imported" or used in an ESM flow,
// it is ok to keep it here for now
json = require(path)
} catch (e) {
fatal(`it seems like ${config} is malformed.`)
}
/**
* Metalsmith.
*/
const metalsmith = new Metalsmith(confRelativeDir)
if (json.source) metalsmith.source(json.source)
if (json.destination) metalsmith.destination(json.destination)
if (json.concurrency) metalsmith.concurrency(json.concurrency)
if (json.metadata) metalsmith.metadata(json.metadata)
if (json.clean != null) metalsmith.clean(json.clean)
if (json.frontmatter != null) metalsmith.frontmatter(json.frontmatter)
if (json.ignore != null) metalsmith.ignore(json.ignore)
if (isObject(json.env)) metalsmith.env(expandEnvVars(json.env, process.env))
// set a flag plugins can check to target CLI-specific behavior
metalsmith.env('CLI', true)
/**
* Plugins.
*/
normalize(json.plugins).forEach(function (plugin) {
for (const name in plugin) {
const opts = plugin[name]
let mod
try {
const local = resolve(confRelativeDir, name)
const npm = resolve(confRelativeDir, 'node_modules', name)
if (exists(local) || exists(`${local}.js`)) {
mod = require(local)
} else if (exists(npm)) {
mod = require(npm)
} else {
mod = require(name)
}
} catch (e) {
fatal(`failed to require plugin "${name}".`)
}
try {
metalsmith.use(mod(opts))
} catch (e) {
fatal(`error using plugin "${name}"...`, `${e.message}\n\n${e.stack}`)
}
}
})
/**
* Build.
*/
metalsmith.build(function (err) {
if (err) fatal(err.message, err.stack)
log('success', `successfully built to ${metalsmith.destination()}`)
})
/**
* Log an error and then exit the process.
*
* @param {String} msg
* @param {String} [stack] Optional stack trace to print.
*/
function fatal(msg, stack) {
log('error', msg)
if (stack) {
log('error', stack)
}
// eslint-disable-next-line no-process-exit
process.exit(1)
}
function log(type, msg) {
if (!msg) {
msg = type
}
const fn = console[type] || console.log
let args = [`Metalsmith · ${msg}`,'\x1b[0m']
if (color[type]) args = [color[type], ...args]
fn(...args)
}
/**
* Normalize an `obj` of plugins.
*
* @param {Array or Object} obj
* @return {Array}
*/
function normalize(obj) {
if (obj instanceof Array) return obj
const ret = []
for (const key in obj) {
const plugin = {}
plugin[key] = obj[key]
ret.push(plugin)
}
return ret
}
/**
* Expand env var values in env with values in expansionSource
* @param {Object} env
* @param {Object} expansionSource
* @returns {Object}
*/
function expandEnvVars(env, expansionSource) {
Object.entries(env).forEach(([name, value]) => {
if (isString(value) && value.startsWith('$')) {
env[name] = expansionSource[value.slice(1)]
}
}, env)
return env
}