Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bin/faucet
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
let { faucetDispatch } = require("../lib");
let { parseCLI } = require("../lib/cli");

let { referenceDir, config, options } = parseCLI();
faucetDispatch(referenceDir, config, options);
parseCLI().
then(({ referenceDir, config, options }) => {
faucetDispatch(referenceDir, config, options);
});
4 changes: 2 additions & 2 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Options:
serve generated files via HTTP with live reloading
`.trim();

exports.parseCLI = function parseCLI(argv = process.argv.slice(2), help = HELP) {
exports.parseCLI = async function parseCLI(argv = process.argv.slice(2), help = HELP) {
argv = parseArgs(argv, {
boolean: ["watch", "fingerprint", "sourcemaps", "compact"],
alias: {
Expand Down Expand Up @@ -56,6 +56,6 @@ exports.parseCLI = function parseCLI(argv = process.argv.slice(2), help = HELP)
}

let rootDir = process.cwd();
let { referenceDir, config } = readConfig(rootDir, argv.config);
let { referenceDir, config } = await readConfig(rootDir, argv.config);
return { referenceDir, config, options };
};
4 changes: 2 additions & 2 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

let path = require("path");

exports.readConfig = function readConfig(rootDir, filepath = "faucet.config.js") {
exports.readConfig = async function readConfig(rootDir, filepath = "faucet.config.js") {
let configPath = path.resolve(rootDir, filepath);
return {
referenceDir: path.dirname(configPath),
config: require(configPath)
config: await require(configPath)
};
};
12 changes: 7 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ exports.faucetDispatch = async function faucetDispatch(referenceDir, config,
browsers = [browsers];
}

let plugins = pluginsByBucket(config);
let plugins = await pluginsByBucket(config);
// initialize plugins with corresponding configuration
let buckets = Object.keys(plugins).reduce((memo, bucket) => {
memo[bucket] = plugins[bucket].map(({ plugin, config }) => {
Expand All @@ -40,8 +40,10 @@ exports.faucetDispatch = async function faucetDispatch(referenceDir, config,

if(watch) {
makeWatcher(config.watchDirs, referenceDir).
on("edit", filepaths => {
runner.rerun(filepaths);
then(watcher => {
watcher.on("edit", filepaths => {
runner.rerun(filepaths);
});
});
}

Expand All @@ -60,8 +62,8 @@ function buildStep(plugins) {
then(() => files);
}

function makeWatcher(watchDirs, referenceDir) {
let niteOwl = require("nite-owl");
async function makeWatcher(watchDirs, referenceDir) {
let niteOwl = await require("nite-owl");

if(watchDirs) {
watchDirs = watchDirs.map(dir => resolvePath(dir, referenceDir,
Expand Down
43 changes: 23 additions & 20 deletions lib/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,50 @@ module.exports = {

// returns plugin functions grouped by bucket and filtered by relevance (based
// on configuration)
function pluginsByBucket(config, defaults) {
let plugins = determinePlugins(config.plugins, defaults);
async function pluginsByBucket(config, defaults) {
let plugins = await determinePlugins(config.plugins, defaults);
let buckets = [...BUCKETS].reduce((memo, bucket) => {
memo[bucket] = [];
return memo;
}, {});
Object.entries(plugins).forEach(([key, _plugin]) => {
for(let [key, _plugin] of Object.entries(plugins)) {
let pluginConfig = config[key];
if(!pluginConfig) {
return;
continue;
}

let { bucket, plugin } = _plugin;
if(!plugin.call) {
({ plugin } = await loadPlugin(plugin));
}
buckets[bucket].push({
plugin: plugin.call ? plugin : loadPlugin(plugin).plugin,
plugin,
config: pluginConfig
});
});
}
return buckets;
}

// `plugins` is an array of plugins, each either a package identifier or a
// `{ key, bucket, plugin }` object`, with `key` being the configuration key and
// `plugin` being either a function or a package identifier
function determinePlugins(plugins = [], defaults = DEFAULTS) {
async function determinePlugins(plugins = [], defaults = DEFAULTS) {
let registry = {};
// NB: default plugins are resolved lazily because eager loading would
// result in them becoming a hard dependency rather than a convenience
// preset - however, that requires us to duplicate the respective
// configuration keys and buckets here
defaults.forEach(plugin => {
registerPlugin(registry, plugin, false);
});
plugins.forEach(plugin => {
registerPlugin(registry, plugin, true);
});
for(let plugin of defaults) {
await registerPlugin(registry, plugin, false);
}
for(let plugin of plugins) {
await registerPlugin(registry, plugin, true);
}
return registry;
}

function registerPlugin(registry, _plugin, eager) {
let { key, bucket, plugin } = resolvePlugin(_plugin, eager);
async function registerPlugin(registry, _plugin, eager) {
let { key, bucket, plugin } = await resolvePlugin(_plugin, eager);
// NB: default plugins may be overridden
if(registry[key] && !DEFAULT_KEYS.has(key)) {
abort(`ERROR: duplicate plugin key ${repr(key, false)}`);
Expand All @@ -84,14 +87,14 @@ function registerPlugin(registry, _plugin, eager) {
}
}

function resolvePlugin(_plugin, eager) {
async function resolvePlugin(_plugin, eager) {
if(_plugin.substr) { // package identifier
_plugin = loadPlugin(_plugin);
_plugin = await loadPlugin(_plugin);
}

let { key, bucket, plugin } = _plugin;
if(eager && plugin.substr && (!key || !bucket)) { // auto-configuration
let _plugin = loadPlugin(plugin);
let _plugin = await loadPlugin(plugin);
plugin = _plugin.plugin;
// local configuration takes precedence
key = key || _plugin.key;
Expand All @@ -104,13 +107,13 @@ function resolvePlugin(_plugin, eager) {
return { key, bucket, plugin };
}

function loadPlugin(pkg) {
async function loadPlugin(pkg) {
let fail = prop => abort(`ERROR: invalid plugin ${repr(pkg)}; ` +
`missing ${repr(prop, false)}`);
let {
key = fail("key"),
bucket = fail("bucket"),
plugin = fail("plugin")
} = loadExtension(pkg, "ERROR: missing plugin");
} = await loadExtension(pkg, "ERROR: missing plugin");
return { key, bucket, plugin };
}
14 changes: 6 additions & 8 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ let DEFAULTS = {
port: 3000
};

exports.static = (config, webroot) => {
let donny = loadExtension("donny", "failed to activate server");
exports.static = async (config, webroot) => {
let donny = await loadExtension("donny", "failed to activate server");
let [host, port] = parseHost(config);

donny({ port, bind: host, webroot }).
then(() => {
console.error(`serving ${repr(webroot)} at http://${host}:${port}`);
});
await donny({ port, bind: host, webroot });
console.error(`serving ${repr(webroot)} at http://${host}:${port}`);
};

exports.live = (config, root) => {
let liveServer = loadExtension("live-server", "failed to activate live-server");
exports.live = async (config, root) => {
let liveServer = await loadExtension("live-server", "failed to activate live-server");
let [host, port] = parseHost(config);

liveServer.start({ port, host, root, open: false });
Expand Down
8 changes: 4 additions & 4 deletions lib/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ exports.reportFileStatus = (filepath, referenceDir, error) => {
console.error(error ? `✗ ${ref}: ${error.message || error}` : `✓ ${ref}`);
};

// attempts to `require` a module, prompting the user to install the
// corresponding package if it is unavailable
exports.loadExtension = (pkg, errorMessage, supplier = pkg) => {
// attempts to load a module, prompting the user to install the corresponding
// package if it is unavailable
exports.loadExtension = async (pkg, errorMessage, supplier = pkg) => {
try {
return require(pkg);
return await require(pkg);
} catch(err) {
if(err.code !== "MODULE_NOT_FOUND") {
throw err;
Expand Down
62 changes: 31 additions & 31 deletions test/test_plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ describe("plugin registration", () => {
updateNodePath(NODE_PATH);
});

it("only loads default plugins referenced within configuration", () => {
let res = pluginsByBucket({
it("only loads default plugins referenced within configuration", async () => {
let res = await pluginsByBucket({
js: [{ foo: "lorem" }]
});
assertDeep(normalizeAll(res), {
Expand All @@ -53,7 +53,7 @@ describe("plugin registration", () => {
markup: []
});

res = pluginsByBucket({
res = await pluginsByBucket({
sass: [{ bar: "ipsum" }]
});
assertDeep(normalizeAll(res), {
Expand All @@ -66,7 +66,7 @@ describe("plugin registration", () => {
markup: []
});

res = pluginsByBucket({
res = await pluginsByBucket({
js: [{ foo: "lorem" }],
sass: [{ bar: "ipsum" }]
});
Expand All @@ -84,8 +84,8 @@ describe("plugin registration", () => {
});
});

it("allows overriding default plugins", () => {
let res = pluginsByBucket({
it("allows overriding default plugins", async () => {
let res = await pluginsByBucket({
js: [{ foo: "bar" }],
plugins: [{
key: "js",
Expand Down Expand Up @@ -120,20 +120,20 @@ describe("plugin resolution", () => {
updateNodePath(NODE_PATH);
});

it("provides a default set of plugins", () => {
let res = _determinePlugins();
it("provides a default set of plugins", async () => {
let res = await _determinePlugins();
assertDeep(normalizePlugins(res), DEFAULTS);
});

it("supports custom plugins", () => {
it("supports custom plugins", async () => {
// plugin function within configuration
let anon = () => {};
let config = [{
key: "dummy",
bucket: "static",
plugin: anon
}];
let res = _determinePlugins(config);
let res = await _determinePlugins(config);
assertDeep(normalizePlugins(res), Object.assign({}, DEFAULTS, {
dummy: {
bucket: "static",
Expand All @@ -144,7 +144,7 @@ describe("plugin resolution", () => {
// nested package identifier
let pkg = "faucet-pipeline-dummy";
config[0].plugin = pkg;
res = _determinePlugins(config);
res = await _determinePlugins(config);
assertDeep(normalizePlugins(res), Object.assign({}, DEFAULTS, {
dummy: {
bucket: "static",
Expand All @@ -154,7 +154,7 @@ describe("plugin resolution", () => {
}));

// simple package identifier
res = _determinePlugins([pkg]);
res = await _determinePlugins([pkg]);
assertDeep(normalizePlugins(res), Object.assign({}, DEFAULTS, {
dummy: {
bucket: "static",
Expand All @@ -163,12 +163,12 @@ describe("plugin resolution", () => {
}));
});

it("allows overriding plugins' default configuration", () => {
it("allows overriding plugins' default configuration", async () => {
let config = [{
key: "yummy",
plugin: "faucet-pipeline-dummy"
}];
let res = _determinePlugins(config);
let res = await _determinePlugins(config);
assertDeep(normalizePlugins(res), Object.assign({}, DEFAULTS, {
yummy: {
bucket: "static",
Expand All @@ -177,7 +177,7 @@ describe("plugin resolution", () => {
}));

config[0].bucket = "styles";
res = _determinePlugins(config);
res = await _determinePlugins(config);
assertDeep(normalizePlugins(res), Object.assign({}, DEFAULTS, {
yummy: {
bucket: "styles",
Expand All @@ -188,12 +188,12 @@ describe("plugin resolution", () => {
});

it("balks at invalid package identifiers", () => {
assert.throws(() => {
_determinePlugins(["faucet-pipeline-yummy"]);
assert.rejects(async () => {
return _determinePlugins(["faucet-pipeline-yummy"]);
}, /exit 1/);

assert.throws(() => {
_determinePlugins([{
assert.rejects(() => {
return _determinePlugins([{
// NB: local configuration must not be comprehensive to ensure
// plugin is loaded
key: "yummy",
Expand All @@ -203,8 +203,8 @@ describe("plugin resolution", () => {
});

it("balks at duplicate configuration keys", () => {
assert.throws(() => {
_determinePlugins([{
assert.rejects(() => {
return _determinePlugins([{
key: "dummy",
bucket: "static",
plugin: () => {}
Expand All @@ -217,16 +217,16 @@ describe("plugin resolution", () => {
});

it("balks at invalid plugins", () => {
assert.throws(() => {
_determinePlugins(["faucet-pipeline-invalid-a"]);
assert.rejects(() => {
return _determinePlugins(["faucet-pipeline-invalid-a"]);
}, /exit 1/);

assert.throws(() => {
_determinePlugins(["faucet-pipeline-invalid-b"]);
assert.rejects(() => {
return _determinePlugins(["faucet-pipeline-invalid-b"]);
}, /exit 1/);

assert.throws(() => {
_determinePlugins(["faucet-pipeline-invalid-c"]);
assert.rejects(() => {
return _determinePlugins(["faucet-pipeline-invalid-c"]);
}, /exit 1/);
});

Expand All @@ -237,14 +237,14 @@ describe("plugin resolution", () => {
};
["static", "scripts", "styles", "markup"].forEach(bucket => {
plugin.bucket = bucket;
assert.doesNotThrow(() => {
_determinePlugins([plugin]);
assert.doesNotReject(() => {
return _determinePlugins([plugin]);
}, /exit 1/);
});

plugin.bucket = "dummy";
assert.throws(() => {
_determinePlugins([plugin]);
assert.rejects(() => {
return _determinePlugins([plugin]);
}, /exit 1/);
});
});
Expand Down