Skip to content

Commit 45a4afe

Browse files
committed
Added Metalsmith CLI support for loading a .(c)js config. Reads from metalsmith.js as second default after metalsmith.json
1 parent 4929bc2 commit 45a4afe

File tree

10 files changed

+73
-7
lines changed

10 files changed

+73
-7
lines changed

bin/metalsmith

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const readFileSync = require('fs').readFileSync
77
const Metalsmith = require('..')
88
const { Command } = require('commander')
99
const program = new Command()
10-
const { resolve, isAbsolute, dirname } = require('path')
10+
const { resolve, isAbsolute, dirname, extname } = require('path')
1111
const { isString, isObject } = require('../lib/helpers')
1212

1313
const color = {
@@ -51,21 +51,38 @@ program.parse(process.argv)
5151

5252
function buildCommand({ config, ...options }) {
5353
const dir = process.cwd()
54-
const path = isAbsolute(config) ? config : resolve(dir, config)
54+
let path = isAbsolute(config) ? config : resolve(dir, config)
5555

5656
// Important addition of 2.5.x. Given local plugins with a relative path are written with __dirname in mind,
5757
// having a config-relative dir path makes sure the CLI runs properly
5858
// when the command is executed from a subfolder or outside of the ms directory
5959
const confRelativeDir = dirname(path)
60-
if (!exists(path)) fatal(`could not find a ${config} configuration file.`)
60+
if (!exists(path)) {
61+
// commander only supports a single default, so we must set default manually here
62+
if (exists(resolve(confRelativeDir, 'metalsmith.js'))) {
63+
path = resolve(confRelativeDir, 'metalsmith.js')
64+
} else {
65+
fatal(`could not find a ${config} configuration file.`)
66+
}
67+
}
68+
69+
const format = extname(path).slice(1)
6170

6271
let json
6372
try {
64-
// requiring json is incompatible with ESM, however given the metalsmith CLI is not meant to be "imported" or used in an ESM flow,
65-
// it is ok to keep it here for now
66-
json = JSON.parse(readFileSync(path, 'utf-8'))
73+
if (format === 'js' || format === 'cjs') {
74+
json = require(path)
75+
// when a JS file is required that forgets to export using exports or module.exports,
76+
// node instead returns an empty object. Though Metalsmith should in theory consider this a valid config
77+
// for a simple copy -> paste it is highly likely that this was not the user's intension
78+
if (isObject(json) && Object.keys(json).length === 0) {
79+
fatal(`it seems like ${config} is empty. Make sure it exports a metalsmith config object.`)
80+
}
81+
} else {
82+
json = JSON.parse(readFileSync(path, 'utf-8'))
83+
}
6784
} catch (e) {
68-
fatal(`it seems like ${config} is malformed.`)
85+
fatal(`it seems like ${config} is malformed or unsupported (ESM).`)
6986
}
7087

7188
/**

test/fixtures/cli-js/config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"source": "source",
3+
"destination": "destination"
4+
}

test/fixtures/cli-js/config.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const config = {
2+
"source": "source",
3+
"destination": "destination"
4+
}
5+
export default config
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
body
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
body

test/fixtures/cli-js/metalsmith.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"source": "source",
3+
"destination": "destination"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"source": "source",
3+
"destination": "destination"
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
body
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
body

test/index.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,34 @@ describe('CLI', function () {
12611261
})
12621262
})
12631263

1264+
it('should grab config from <configname>.(c)js', function (done) {
1265+
let doneCounter = 0
1266+
exec(bin, { cwd: fixture('cli-js') }, function (err, stdout) {
1267+
if (err) return done(err)
1268+
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
1269+
assert(~stdout.indexOf('successfully built to '))
1270+
assert(~stdout.indexOf(fixture('cli-js/destination')))
1271+
if (doneCounter === 2) done()
1272+
else doneCounter += 1
1273+
})
1274+
exec(bin + ' -c config.cjs', { cwd: fixture('cli-js') }, function (err, stdout) {
1275+
if (err) return done(err)
1276+
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
1277+
assert(~stdout.indexOf('successfully built to '))
1278+
assert(~stdout.indexOf(fixture('cli-js/destination')))
1279+
if (doneCounter === 2) done()
1280+
else doneCounter += 1
1281+
})
1282+
exec(bin + ' -c other-config.cjs', { cwd: fixture('cli-js') }, function (err, stdout) {
1283+
if (err) return done(err)
1284+
equal(fixture('cli-js/destination'), fixture('cli-js/expected'))
1285+
assert(~stdout.indexOf('successfully built to '))
1286+
assert(~stdout.indexOf(fixture('cli-js/destination')))
1287+
if (doneCounter === 2) done()
1288+
else doneCounter += 1
1289+
})
1290+
})
1291+
12641292
it('should require a plugin', function (done) {
12651293
exec(bin, { cwd: fixture('cli-plugin-object') }, function (err, stdout) {
12661294
if (err) return done(err)

0 commit comments

Comments
 (0)