diff --git a/examples/multiple-dirs/css/buttons.css b/examples/multiple-dirs/css/buttons.css new file mode 100644 index 0000000..6938705 --- /dev/null +++ b/examples/multiple-dirs/css/buttons.css @@ -0,0 +1,23 @@ +/** + * Buttons + * + * The Button `.btn` class can be applied to ` + * + * Anchor + */ +.btn { + background-color: #ddd; + border-radius: 4px; + border: 2px solid transparent; + color: black; + display: inline-block; + font-size: 16px; + line-height: 1; + padding: 5px 15px; + text-decoration: none; +} diff --git a/examples/multiple-dirs/index.js b/examples/multiple-dirs/index.js new file mode 100644 index 0000000..8e423d7 --- /dev/null +++ b/examples/multiple-dirs/index.js @@ -0,0 +1,16 @@ +var path = require('path'); + +var livingcss = require('../../index'); + +(async function() { + try { + // all these methods should work: + await livingcss('css/buttons.css', 'styleguide'); + // await livingcss(path.join(__dirname, 'css/buttons.css'), 'styleguide'); + // await livingcss(path.join(__dirname, 'css/buttons.css'), path.join(__dirname, 'styleguide')); + // await livingcss('css/buttons.css', path.join(__dirname, 'styleguide')); + } catch (err) { + console.error(err); + console.error(err.stack); + } +})(); diff --git a/lib/generate.js b/lib/generate.js index e8a8341..8f79ddd 100644 --- a/lib/generate.js +++ b/lib/generate.js @@ -55,13 +55,30 @@ function generate(dest, template, context, options) { } return preprocess - .then(function() { + .then(async function() { // inline all stylesheets for polymer shared styles to work // @see https://www.polymer-project.org/1.0/docs/devguide/styling#style-modules - return utils.readFiles(context.stylesheets, function(data, file) { + + const parsedStylesheetFile = function(data, file) { context.parsedStylesheets = context.parsedStylesheets || []; context.parsedStylesheets.push(utils.fixSVGIssue(data)); - }); + }; + + let fileList; + try { + fileList = await utils.readFiles(context.stylesheets, parsedStylesheetFile); + } catch (err) { + if ('ENOENT' !== err.code) { + throw err; + } + const destDir = path.dirname(dest); + const stylesheets = context.stylesheets.map((file) => { + return path.resolve(destDir, file); + }); + fileList = await utils.readFiles(stylesheets, parsedStylesheetFile); + } + + return fileList; }) .then(function success() { var html = Handlebars.compile(template)(context); @@ -94,4 +111,4 @@ function generate(dest, template, context, options) { }); } -module.exports = generate; \ No newline at end of file +module.exports = generate; diff --git a/lib/utils.js b/lib/utils.js index 5b778dd..4857d2d 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -16,9 +16,8 @@ utils._readFileWithPromise = function readFileWithPromise(file) { return new Promise((resolve, reject) => { fs.readFile(file, 'utf8', function(err, data) { if (err) { - reject(err); + return reject(err); } - resolve(data); }); }); @@ -29,11 +28,11 @@ utils._readFileWithPromise = function readFileWithPromise(file) { * @param {string} pattern - Glob file pattern * @returns Promise */ -function globWithPromsie(pattern) { +function globWithPromise(pattern) { return new Promise((resolve, reject) => { glob(pattern, function(err, files) { if (err) { - reject(err); + return reject(err); } if (files.length === 0) { @@ -153,7 +152,7 @@ utils.sortCategoryBy = function sortCategoryBy(categories, sortOrder) { utils.readFileGlobs = async function readFileGlobs(patterns, callback) { patterns = (!Array.isArray(patterns) ? [patterns] : patterns); let globPromises = await patterns.map(async (pattern) => { - return globWithPromsie(pattern); + return globWithPromise(pattern); }); return Promise.all(globPromises) @@ -162,7 +161,7 @@ utils.readFileGlobs = async function readFileGlobs(patterns, callback) { // fileList is an array of arrays of files // e.g. [ [fileOne, fileTwo], [fileThree, fileFour], ...] let readFilePromises = await fileList.map(async (files) => { - return await utils.readFiles(files) + return await utils.readFiles(files); }); return Promise.all(readFilePromises); @@ -187,24 +186,27 @@ utils.readFileGlobs = async function readFileGlobs(patterns, callback) { * @param {function} callback - Callback to execute for each read file. * @returns {Promise} */ -utils.readFiles = async function readFiles(files, callback) { - if (!files || (Array.isArray(files) && !files.length)) return Promise.resolve(); +utils.readFiles = function readFiles(files, callback) { + if (!files || (Array.isArray(files) && !files.length)) return Promise.resolve([]); files = (!Array.isArray(files) ? [files] : files); - let promises = await Promise.all(files.map(async (file) => { + return Promise.all(files.map(async (file) => { let data = await utils._readFileWithPromise(file); return [data, file]; - })); - - return Promise.all(promises).then(files => { - if (callback) { - files.forEach(function(data) { - callback.apply(null, data); - }); - } - - return files; - }) + })) + .then(async files => { + if (callback) { + const promises = []; + files.forEach(function(data) { + const result = callback.apply(null, data); + if ('object' === typeof result && result.then) { + promises.push(result); + } + }); + await Promise.all(promises); + } + return files; + }); } /** diff --git a/package-lock.json b/package-lock.json index e8e3826..e98dca2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -895,6 +895,15 @@ "type-detect": "^4.0.5" } }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -2180,7 +2189,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2201,12 +2211,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2221,17 +2233,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2348,7 +2363,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2360,6 +2376,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2374,6 +2391,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2381,12 +2399,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2405,6 +2425,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2485,7 +2506,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2497,6 +2519,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2582,7 +2605,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2618,6 +2642,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2637,6 +2662,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2680,12 +2706,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index 025dae6..e462c69 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,37 @@ { - "name": "livingcss", - "version": "6.0.3", - "description": "Generate a style guide using comment driven content creation", - "main": "index.js", - "scripts": { - "test": "nyc --reporter=lcov --reporter=text mocha" + "_from": "livingcss", + "_id": "livingcss@6.0.3", + "_inBundle": false, + "_integrity": "sha512-CqClAsCzLbwePqpFfieEvwNgevgSLCbCcTFvGnlP2ewvVcVa8dmKtdtcYt+DrOjCpoTYgzKnpgyhhfiCDjdZkQ==", + "_location": "/livingcss", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "livingcss", + "name": "livingcss", + "escapedName": "livingcss", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" }, - "repository": { - "type": "git", - "url": "https://github.com/straker/livingcss.git" - }, - "keywords": [ - "style", - "guide", - "generator", - "css" + "_requiredBy": [ + "#DEV:/", + "#USER" ], - "author": "Steven Lambert (http://sklambert.com/)", - "license": "MIT", + "_resolved": "https://registry.npmjs.org/livingcss/-/livingcss-6.0.3.tgz", + "_shasum": "7f2eeb07dd42734029f2962ad1b8751cab252eb2", + "_spec": "livingcss", + "_where": "/Users/matmar10/Projects/Blossom/bootstrap-theme", + "author": { + "name": "Steven Lambert", + "email": "steven@sklambert.com", + "url": "http://sklambert.com/" + }, "bugs": { "url": "https://github.com/straker/livingcss/issues" }, - "homepage": "https://github.com/straker/livingcss", + "bundleDependencies": false, "dependencies": { "comment-parser": "^0.5.4", "glob": "^7.1.3", @@ -31,8 +41,11 @@ "mkdirp": "^0.5.1", "normalize-newline": "^3.0.0" }, + "deprecated": false, + "description": "Generate a style guide using comment driven content creation", "devDependencies": { "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", "coveralls": "^3.0.3", "gulp": "^4.0.1", "gulp-connect": "^5.7.0", @@ -49,5 +62,23 @@ "nyc": "^14.1.0", "proxyquire": "^1.8.0", "sinon": "^4.2.2" - } + }, + "homepage": "https://github.com/straker/livingcss", + "keywords": [ + "style", + "guide", + "generator", + "css" + ], + "license": "MIT", + "main": "index.js", + "name": "livingcss", + "repository": { + "type": "git", + "url": "git+https://github.com/straker/livingcss.git" + }, + "scripts": { + "test": "nyc --reporter=lcov --reporter=text mocha" + }, + "version": "6.0.3" } diff --git a/test/utils.spec.js b/test/utils.spec.js index 8065031..83dbbcb 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,10 +1,14 @@ /*jshint -W030 */ -var expect = require('chai').expect; +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); var sinon = require('sinon'); var proxyquire = require('proxyquire'); var normalizeNewline = require('normalize-newline'); +chai.use(chaiAsPromised); +var expect = chai.expect; + // stubs var fsStub = { writeFile: function(file, data, options, callback) { callback(null); }, @@ -18,7 +22,7 @@ var globStub = function(files, callback) { if (files instanceof Error) return callback(files); files = (!Array.isArray(files) ? [files] : files); callback(null, files); -} +}; var utils = proxyquire('../lib/utils', { fs: fsStub, @@ -243,16 +247,14 @@ describe('utils', function() { }); }); - it('should handle error', function(done) { - var file = new Error('custom cannot read file'); + it('should notify of error', function() { + var promise = utils.readFiles(new Error('custom cannot read file')); + return expect(promise).to.eventually.be.rejectedWith(Error); + }); - utils.readFiles(file) - .then(function() { - done('readFiles did not throw error'); - }) - .catch(function(err) { - done(); - }); + it('should return empty array if no files', function() { + var promise = utils.readFiles([]); + return expect(promise).to.eventually.deep.equal([]); }); }); @@ -341,30 +343,15 @@ describe('utils', function() { }); }); - it('should handle glob error', function(done) { - var files = new Error('custom: glob error'); - - utils.readFileGlobs(files) - .then(function() { - done('readFileGlobs did not throw error'); - }) - .catch(function(err) { - expect(err.message).to.equal('custom: glob error'); - done(); - }); + it('should handle glob error', async function() { + var promise = utils.readFileGlobs(new Error('custom: glob error')); + return expect(promise).to.be.rejectedWith(Error); }); - it('should handle read file error', function(done) { + it('should handle read file error', function() { var files = '__ERROR__'; - - utils.readFileGlobs(files) - .then(function() { - done('readFileGlobs did not throw error'); - }) - .catch(function(err) { - expect(err).to.equal('readFile error'); - done(); - }); + var promise = utils.readFileGlobs(files); + return expect(promise).to.be.rejected; }); }); @@ -402,4 +389,4 @@ describe('utils', function() { expect(utils.fixSVGIssue(testString)).to.equal(testString); }); }); -}); \ No newline at end of file +});