Skip to content

Commit

Permalink
Added Metalsmith CLI support for loading a .(c)js config. Reads from …
Browse files Browse the repository at this point in the history
…metalsmith.js as second default after metalsmith.json
  • Loading branch information
webketje committed Jan 21, 2023
1 parent 4929bc2 commit 45a4afe
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 7 deletions.
31 changes: 24 additions & 7 deletions bin/metalsmith
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const readFileSync = require('fs').readFileSync
const Metalsmith = require('..')
const { Command } = require('commander')
const program = new Command()
const { resolve, isAbsolute, dirname } = require('path')
const { resolve, isAbsolute, dirname, extname } = require('path')
const { isString, isObject } = require('../lib/helpers')

const color = {
Expand Down Expand Up @@ -51,21 +51,38 @@ program.parse(process.argv)

function buildCommand({ config, ...options }) {
const dir = process.cwd()
const path = isAbsolute(config) ? config : resolve(dir, config)
let 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.`)
if (!exists(path)) {
// commander only supports a single default, so we must set default manually here
if (exists(resolve(confRelativeDir, 'metalsmith.js'))) {
path = resolve(confRelativeDir, 'metalsmith.js')
} else {
fatal(`could not find a ${config} configuration file.`)
}
}

const format = extname(path).slice(1)

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 = JSON.parse(readFileSync(path, 'utf-8'))
if (format === 'js' || format === 'cjs') {
json = require(path)
// when a JS file is required that forgets to export using exports or module.exports,
// node instead returns an empty object. Though Metalsmith should in theory consider this a valid config
// for a simple copy -> paste it is highly likely that this was not the user's intension
if (isObject(json) && Object.keys(json).length === 0) {
fatal(`it seems like ${config} is empty. Make sure it exports a metalsmith config object.`)
}
} else {
json = JSON.parse(readFileSync(path, 'utf-8'))
}
} catch (e) {
fatal(`it seems like ${config} is malformed.`)
fatal(`it seems like ${config} is malformed or unsupported (ESM).`)
}

/**
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/cli-js/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"source": "source",
"destination": "destination"
}
5 changes: 5 additions & 0 deletions test/fixtures/cli-js/config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const config = {
"source": "source",
"destination": "destination"
}
export default config
1 change: 1 addition & 0 deletions test/fixtures/cli-js/destination/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body
1 change: 1 addition & 0 deletions test/fixtures/cli-js/expected/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body
4 changes: 4 additions & 0 deletions test/fixtures/cli-js/metalsmith.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"source": "source",
"destination": "destination"
}
4 changes: 4 additions & 0 deletions test/fixtures/cli-js/other-config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"source": "source",
"destination": "destination"
}
1 change: 1 addition & 0 deletions test/fixtures/cli-js/overriden/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body
1 change: 1 addition & 0 deletions test/fixtures/cli-js/source/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body
28 changes: 28 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,34 @@ describe('CLI', function () {
})
})

it('should grab config from <configname>.(c)js', function (done) {
let doneCounter = 0
exec(bin, { cwd: fixture('cli-js') }, function (err, stdout) {
if (err) return done(err)
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
assert(~stdout.indexOf('successfully built to '))
assert(~stdout.indexOf(fixture('cli-js/destination')))
if (doneCounter === 2) done()
else doneCounter += 1
})
exec(bin + ' -c config.cjs', { cwd: fixture('cli-js') }, function (err, stdout) {
if (err) return done(err)
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
assert(~stdout.indexOf('successfully built to '))
assert(~stdout.indexOf(fixture('cli-js/destination')))
if (doneCounter === 2) done()
else doneCounter += 1
})
exec(bin + ' -c other-config.cjs', { cwd: fixture('cli-js') }, function (err, stdout) {
if (err) return done(err)
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
assert(~stdout.indexOf('successfully built to '))
assert(~stdout.indexOf(fixture('cli-js/destination')))
if (doneCounter === 2) done()
else doneCounter += 1
})
})

it('should require a plugin', function (done) {
exec(bin, { cwd: fixture('cli-plugin-object') }, function (err, stdout) {
if (err) return done(err)
Expand Down

0 comments on commit 45a4afe

Please sign in to comment.