From 02cac8207978824f08eb862d23e3d48ebd81ccd3 Mon Sep 17 00:00:00 2001 From: Nik Butenko Date: Tue, 25 Aug 2015 22:38:59 +1000 Subject: [PATCH 1/5] Add function to look for local scaffolds --- lib/find-scaffolds.js | 16 +++++++----- test/lib/find-scaffolds.js | 53 +++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/find-scaffolds.js b/lib/find-scaffolds.js index 99803e9..2aeead1 100644 --- a/lib/find-scaffolds.js +++ b/lib/find-scaffolds.js @@ -1,10 +1,11 @@ import npm from 'npm'; -const isScaffold = ({keywords = [], name = ''}) => +const isScaffold = ({keywords = [], name}) => name && ( name.substr(0, 3) === 'cf-' || keywords.indexOf('cloverfield-scaffold') !== -1 || - keywords.indexOf('cloverfield') !== -1 && keywords.indexOf('scaffold') !== -1; + keywords.indexOf('cloverfield') !== -1 && keywords.indexOf('scaffold') !== -1 +); const modulesReady = (resolve, reject) => (error, tree) => { @@ -34,9 +35,12 @@ const loaded = (resolve, reject) => (error) => { // TODO: add caching -const findScaffolds = () => - // Configure npm to search for dependencies globally with minimal depth - new Promise((...args) => npm.load({global: true, silent: true, depth: 0}, loaded(...args))); +const findScaffolds = global => () => + // Configure npm to search for dependencies globally or locally with minimal depth + new Promise((...args) => npm.load({global, silent: true, depth: 0}, loaded(...args))); -export default findScaffolds; +export const findLocal = findScaffolds(false); + + +export const findGlobal = findScaffolds(true); diff --git a/test/lib/find-scaffolds.js b/test/lib/find-scaffolds.js index 5e3a979..14142aa 100644 --- a/test/lib/find-scaffolds.js +++ b/test/lib/find-scaffolds.js @@ -3,7 +3,7 @@ import npm from 'npm'; import {stub, spy} from 'sinon'; -import findScaffolds from '../../lib/find-scaffolds'; +import {findLocal, findGlobal} from '../../lib/find-scaffolds'; const dependencies = { @@ -36,6 +36,11 @@ const dependencies = { name: 'incorrectly-tagged', realPath: 'incorrectly-tagged realpath', keywords: ['cloverfield', 'something else'] + }, + packageWithoutName: { + // should skip this because it does not have a name + realPath: 'package-without-name realpath', + keywords: ['cloverfield', 'scaffold'] } }; @@ -58,22 +63,52 @@ const after = () => { }; -test('Find Scaffolds success', assert => { +test('Find Scaffolds API', assert => { + before(); + + + assert.ok(findGlobal instanceof Function, 'should be function'); + assert.ok(findGlobal() instanceof Promise, 'should return Promise'); + + after(); + assert.end(); +}); + + +test('Search for global Scaffolds', assert => { const {load} = before(); - assert.ok(findScaffolds instanceof Function, 'should be function'); + findGlobal(); + assert.equal(load.getCall(0).args[0].global, true, 'should call npm.init with global flag'); - const promise = findScaffolds(); - assert.ok(promise instanceof Promise, 'should return Promise'); + after(); + assert.end(); +}); - assert.ok(load.calledOnce, 'npm.init should be called'); +test('Search for local Scaffolds', assert => { + const {load} = before(); + + + findLocal(); + assert.equal(load.getCall(0).args[0].global, false, 'should call npm.init without global flag'); + + + after(); + assert.end(); +}); + +test('Finding Scaffolds', assert => { + const {load} = before(); + const promise = findGlobal(); + + assert.ok(load.calledOnce, 'npm.init should be called'); - // Emulate successfull load response + // Emulate successful load response const loadCallback = load.getCall(0).args[1]; loadCallback(null); @@ -97,7 +132,7 @@ test('Find Scaffolds success', assert => { test('Find Scaffolds fail on npm.init', assert => { const {load} = before(); - const promise = findScaffolds(); + const promise = findGlobal(); const loadCallback = load.getCall(0).args[1]; @@ -115,7 +150,7 @@ test('Find Scaffolds fail on npm.init', assert => { test('Find Scaffolds fail on npm.commands.ls', assert => { const {load} = before(); - const promise = findScaffolds(); + const promise = findGlobal(); const loadCallback = load.getCall(0).args[1]; loadCallback(null); From 2e2dd0733e77fbe33c1535a5a0355bbec4b2c308 Mon Sep 17 00:00:00 2001 From: Nik Butenko Date: Tue, 25 Aug 2015 23:20:30 +1000 Subject: [PATCH 2/5] Search for both local and global packages --- lib/cli.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index b356ccd..de34c3d 100755 --- a/lib/cli.js +++ b/lib/cli.js @@ -4,7 +4,7 @@ import 'babel/polyfill'; import nomnom from 'nomnom'; import cloverfield from './cloverfield'; -import findScaffolds from './find-scaffolds'; +import {findGlobal, findLocal} from './find-scaffolds'; import buildCommand from './commands/build'; @@ -12,8 +12,10 @@ const parser = nomnom(); Promise.all([ - findScaffolds() + Promise.all([findLocal(), findGlobal()]) .catch(console.error.bind(console)) + // Prefer local packages over global + .then(([local, global]) => ({...global, ...local})) .then(buildCommand) ]) .then(cloverfield(parser)) From dfad3ffb64fb19a793fe524adf22c27cf491367b Mon Sep 17 00:00:00 2001 From: Nik Butenko Date: Tue, 25 Aug 2015 23:21:27 +1000 Subject: [PATCH 3/5] Parse package's config and require correct CLI file --- lib/commands/build.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/commands/build.js b/lib/commands/build.js index 686e96e..0c4c97d 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -1,3 +1,5 @@ +import path from 'path'; + export default scaffolds => { const command = 'build'; @@ -12,8 +14,12 @@ export default scaffolds => { } }; - const callback = ({scaffold, ...opts}) => - require(scaffolds[scaffold])(opts); + const callback = ({scaffold, ...opts}) => { + const packageJson = require(path.join(scaffolds[scaffold], 'package.json')); + const cli = require(path.join(scaffolds[scaffold], packageJson.main)); + + return cli(opts); + }; const help = 'Build a new package from a Cloverfield scaffold'; From e2d6827faa588625dbf74c0d0e36b13e0b75ac76 Mon Sep 17 00:00:00 2001 From: Nik Butenko Date: Sat, 29 Aug 2015 18:08:49 +1000 Subject: [PATCH 4/5] Pass npm to find-scaffolds to keep it pure --- lib/cli.js | 3 +- lib/find-scaffolds.js | 13 +++--- test/lib/find-scaffolds.js | 81 +++++++++++++++----------------------- 3 files changed, 39 insertions(+), 58 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index de34c3d..d8dae75 100755 --- a/lib/cli.js +++ b/lib/cli.js @@ -6,13 +6,14 @@ import nomnom from 'nomnom'; import cloverfield from './cloverfield'; import {findGlobal, findLocal} from './find-scaffolds'; import buildCommand from './commands/build'; +import npm from 'npm'; const parser = nomnom(); Promise.all([ - Promise.all([findLocal(), findGlobal()]) + Promise.all([findLocal(npm)(), findGlobal(npm)()]) .catch(console.error.bind(console)) // Prefer local packages over global .then(([local, global]) => ({...global, ...local})) diff --git a/lib/find-scaffolds.js b/lib/find-scaffolds.js index 2aeead1..894197c 100644 --- a/lib/find-scaffolds.js +++ b/lib/find-scaffolds.js @@ -1,6 +1,3 @@ -import npm from 'npm'; - - const isScaffold = ({keywords = [], name}) => name && ( name.substr(0, 3) === 'cf-' || keywords.indexOf('cloverfield-scaffold') !== -1 || @@ -24,7 +21,7 @@ const modulesReady = (resolve, reject) => (error, tree) => { }; -const loaded = (resolve, reject) => (error) => { +const loaded = npm => (resolve, reject) => (error) => { if (error) { return reject(error); } @@ -35,12 +32,12 @@ const loaded = (resolve, reject) => (error) => { // TODO: add caching -const findScaffolds = global => () => +const findScaffolds = npm => global => () => // Configure npm to search for dependencies globally or locally with minimal depth - new Promise((...args) => npm.load({global, silent: true, depth: 0}, loaded(...args))); + new Promise((...args) => npm.load({global, silent: true, depth: 0}, loaded(npm)(...args))); -export const findLocal = findScaffolds(false); +export const findLocal = npm => findScaffolds(npm)(false); -export const findGlobal = findScaffolds(true); +export const findGlobal = npm => findScaffolds(npm)(true); diff --git a/test/lib/find-scaffolds.js b/test/lib/find-scaffolds.js index 14142aa..fade1c1 100644 --- a/test/lib/find-scaffolds.js +++ b/test/lib/find-scaffolds.js @@ -1,6 +1,5 @@ import test from 'blue-tape'; -import npm from 'npm'; -import {stub, spy} from 'sinon'; +import {spy} from 'sinon'; import {findLocal, findGlobal} from '../../lib/find-scaffolds'; @@ -45,71 +44,58 @@ const dependencies = { }; -const before = () => { - // Stubs - const load = spy(); - - stub(npm, 'load', load); - npm.commands = { - ls: spy() +const mockNpm = () => { + const npm = { + load: spy(), + commands: { + ls: spy() + } }; - return {load}; -}; - - -const after = () => { - npm.load.restore(); + return {npm}; }; test('Find Scaffolds API', assert => { - before(); - + const {npm} = mockNpm(); - assert.ok(findGlobal instanceof Function, 'should be function'); - assert.ok(findGlobal() instanceof Promise, 'should return Promise'); + assert.ok(findGlobal(npm) instanceof Function, 'should be function'); + assert.ok(findGlobal(npm)() instanceof Promise, 'should return Promise'); - - after(); assert.end(); }); test('Search for global Scaffolds', assert => { - const {load} = before(); - - - findGlobal(); - assert.equal(load.getCall(0).args[0].global, true, 'should call npm.init with global flag'); + const {npm} = mockNpm(); + findGlobal(npm)(); + assert.equal(npm.load.getCall(0).args[0].global, true, 'should call npm.init with global flag'); - after(); assert.end(); }); test('Search for local Scaffolds', assert => { - const {load} = before(); - - - findLocal(); - assert.equal(load.getCall(0).args[0].global, false, 'should call npm.init without global flag'); + const {npm} = mockNpm(); + findLocal(npm)(); + assert.equal(npm.load.getCall(0).args[0].global, + false, + 'should call npm.init without global flag'); - after(); assert.end(); }); test('Finding Scaffolds', assert => { - const {load} = before(); - const promise = findGlobal(); + const {npm} = mockNpm(); + const promise = findGlobal(npm)(); - assert.ok(load.calledOnce, 'npm.init should be called'); + assert.ok(npm.load.calledOnce, 'npm.init should be called'); // Emulate successful load response - const loadCallback = load.getCall(0).args[1]; + const loadCallback = npm.load.getCall(0).args[1]; loadCallback(null); @@ -125,15 +111,14 @@ test('Finding Scaffolds', assert => { assert.ok(scaffolds, 'find-scaffold should resolve with found scaffolds'); assert.deepEqual(Object.keys(scaffolds), ['test', 'tagged1', 'tagged2'], 'should return correctly matched scaffolds'); - }) - .then(after); + }); }); test('Find Scaffolds fail on npm.init', assert => { - const {load} = before(); - const promise = findGlobal(); - const loadCallback = load.getCall(0).args[1]; + const {npm} = mockNpm(); + const promise = findGlobal(npm)(); + const loadCallback = npm.load.getCall(0).args[1]; loadCallback(new Error('Oops')); @@ -143,15 +128,14 @@ test('Find Scaffolds fail on npm.init', assert => { .catch(error => { assert.ok(error instanceof Error, 'should reject with Error'); assert.equal(error.message, 'Oops', 'should pass-through error message'); - }) - .then(after); + }); }); test('Find Scaffolds fail on npm.commands.ls', assert => { - const {load} = before(); - const promise = findGlobal(); - const loadCallback = load.getCall(0).args[1]; + const {npm} = mockNpm(); + const promise = findGlobal(npm)(); + const loadCallback = npm.load.getCall(0).args[1]; loadCallback(null); @@ -164,6 +148,5 @@ test('Find Scaffolds fail on npm.commands.ls', assert => { .catch(error => { assert.ok(error instanceof Error, 'should reject with Error'); assert.equal(error.message, 'Oops', 'should pass-through error message'); - }) - .then(after); + }); }); From a2bd7515b629c4fa8549880fa0db908e9213aa43 Mon Sep 17 00:00:00 2001 From: Nik Butenko Date: Wed, 2 Sep 2015 08:45:45 +1000 Subject: [PATCH 5/5] Remove boolean trap --- lib/find-scaffolds.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/find-scaffolds.js b/lib/find-scaffolds.js index 894197c..83f1af4 100644 --- a/lib/find-scaffolds.js +++ b/lib/find-scaffolds.js @@ -32,12 +32,12 @@ const loaded = npm => (resolve, reject) => (error) => { // TODO: add caching -const findScaffolds = npm => global => () => +const findScaffolds = npm => options => () => // Configure npm to search for dependencies globally or locally with minimal depth - new Promise((...args) => npm.load({global, silent: true, depth: 0}, loaded(npm)(...args))); + new Promise((...args) => npm.load({silent: true, depth: 0, ...options}, loaded(npm)(...args))); -export const findLocal = npm => findScaffolds(npm)(false); +export const findLocal = npm => findScaffolds(npm)({global: false}); -export const findGlobal = npm => findScaffolds(npm)(true); +export const findGlobal = npm => findScaffolds(npm)({global: true});