diff --git a/lib/media.js b/lib/media.js index fa7b3ac..86347d3 100644 --- a/lib/media.js +++ b/lib/media.js @@ -5,7 +5,6 @@ const _ = require('lodash'), files = require('nymag-fs'), bluebird = require('bluebird'), setup = require('./setup'), - styleguide = require('./styleguide'), STYLE_TAG = 'style', SCRIPT_TAG = 'scripts', MEDIA_DIRECTORY = path.join(process.cwd(), 'public'); @@ -160,91 +159,86 @@ function injectTags(fileArray, site, tag) { /** * Gets a list of all css and js needed for the components listed. - * - * NOTE: the getStyles and getScripts are memoized using all arguments - * - * @param {Array} componentList - * @param {string} slug + * @param {Object} state * @returns {{styles: Array, scripts: Array}} */ -function getMediaMap({ _components:componentList, locals }) { +function getMediaMap(state) { return { - styles: flatMap(componentList, (component) => module.exports.getStyles(component, locals.site)), - scripts: flatMap(componentList, (component) => module.exports.getScripts(component, locals.site)) + styles: module.exports.getStyleFiles(state), + scripts: module.exports.getScriptFiles(state) }; } /** - * Get the proper scripts for the component + * Get the proper styles for the component. If a styleguide is configured, use + * that css. Defaults to the site slug * - * @param {string} name - * @param {object} site + * @param {Object} state * @returns {array} */ -function getScripts(name, site) { - const slug = site.slug, +function getStyleFiles(state) { + const { site } = state.locals, assetDir = site && site.assetDir || MEDIA_DIRECTORY, assetPath = site && site.assetPath || '', - assetHost = site && site.assetHost || ''; - - return _.map(_.filter([ - path.join(assetDir, 'js', `${name}.js`), - path.join(assetDir, 'js', `${name}.${slug}.js`), - path.join(assetDir, 'js', `${name}.client.js`) - ], files.fileExists), pathJoin(assetHost, assetPath, assetDir)); -} + assetHost = site && site.assetHost || '', + siteStyleguide = site && site.styleguide; + let cssFilePaths = []; + + // legacy behavior: load .css and ..css + if (!site.styleguide) { + const siteSlug = site && site.slug; + + cssFilePaths = state._components + .reduce((acc, curr) => { + acc.push( + path.join(assetDir, 'css', `${curr}.css`), + path.join(assetDir, 'css', `${curr}.${siteSlug}.css`) + ); + return acc; + }, []); + // modern behavior: compile all used variations + } else if (state._usedVariations) { + cssFilePaths = state._usedVariations + .map(variation => { + const styleguideVariationPath = path.join(assetDir, 'css', `${variation}.${siteStyleguide}.css`); + + return files.fileExists(styleguideVariationPath) ? + styleguideVariationPath : + path.join(assetDir, 'css', `${variation}._default.css`); + }); + } -/** - * @param {Array} list - * @param {function} fn - * @returns {Array} - */ -function flatMap(list, fn) { - return _.filter(_.flattenDeep(_.map(list, fn)), _.identity); + return cssFilePaths + .filter(files.fileExists) + .map(pathJoin(assetHost, assetPath, assetDir)); } /** - * Get the proper styles for the component. If a styleguide is configured, use - * that css. Defaults to the site slug + * Get the proper scripts for the component * * @param {string} name * @param {object} site * @returns {array} */ -function getStyles(name, site) { - const siteStyleguide = site && site.styleguide, - siteSlug = site && site.slug, + +function getScriptFiles(state) { + const site = state.locals.site, + slug = site.slug, assetDir = site && site.assetDir || MEDIA_DIRECTORY, assetPath = site && site.assetPath || '', assetHost = site && site.assetHost || ''; - let availableVariations, styleguidePath, cssFilePaths; - - if (!siteStyleguide) { - // legacy behavior: load .css and ..css - cssFilePaths = [ - path.join(assetDir, 'css', `${name}.css`), - path.join(assetDir, 'css', `${name}.${siteSlug}.css`) - ]; - } else { - // styleguides: load ..css and _..css - // note: this also loads default styles if the site styleguide doesn't have styles for a certain component / variation - availableVariations = styleguide.getVariations(siteStyleguide); - styleguidePath = path.join(assetDir, 'css', `${name}.${siteStyleguide}.css`); - cssFilePaths = files.fileExists(styleguidePath) ? [styleguidePath] : [path.join(assetDir, 'css', `${name}._default.css`)]; // fall back to default styleguide - - // if there are variations available for the component, add them to the list - // of file paths we want - if (availableVariations[name]) { - availableVariations[name].forEach((variation) => { - let styleguideVariationPath = path.join(assetDir, 'css', `${variation}.${siteStyleguide}.css`); - - cssFilePaths.push(files.fileExists(styleguideVariationPath) ? styleguideVariationPath : path.join(assetDir, 'css', `${variation}._default.css`)); - }); - } - } - - return _.map(_.filter(cssFilePaths, files.fileExists), pathJoin(assetHost, assetPath, assetDir)); + return state._components + .reduce((prev, name) => { + prev.push( + path.join(assetDir, 'js', `${name}.js`), + path.join(assetDir, 'js', `${name}.${slug}.js`), + path.join(assetDir, 'js', `${name}.client.js`) + ); + return prev; + }, []) + .filter(files.fileExists) + .map(pathJoin(assetHost, assetPath, assetDir)); } /** @@ -340,5 +334,5 @@ module.exports.editStylesTags = false; module.exports.editScriptsTags = false; // For testing -module.exports.getScripts = getScripts; -module.exports.getStyles = getStyles; +module.exports.getScriptFiles = getScriptFiles; +module.exports.getStyleFiles = getStyleFiles; diff --git a/lib/media.test.js b/lib/media.test.js index a755420..8690785 100644 --- a/lib/media.test.js +++ b/lib/media.test.js @@ -5,7 +5,6 @@ const _ = require('lodash'), lib = require('./' + filename), expect = require('chai').expect, sinon = require('sinon'), - styleguide = require('./styleguide'), setup = require('./setup'), files = require('nymag-fs'); @@ -40,7 +39,8 @@ describe(_.startCase(filename), function () { slug: 'foo', assetDir: '/foo' } - } + }, + _components: [] }, emptyMediaMap = { scripts: [], @@ -95,198 +95,404 @@ describe(_.startCase(filename), function () { describe('getMediaMap', function () { const fn = lib[this.title]; - it('accepts empty list, empty slug', function () { - expect(fn([])).to.deep.equal({scripts: [], styles: []}); + it('accepts state with empty components', function () { + expect(fn(state)).to.deep.equal({scripts: [], styles: []}); }); it('accepts list, empty slug (non-existent components)', function () { - expect(fn(['a', 'b', 'c'])).to.deep.equal({scripts: [], styles: []}); + expect( + fn( + _.merge( + { + _components: ['a', 'b', 'c'] + }, + _.omit(state, ['locals.site.slug']) + ) + ) + ).to.deep.equal({scripts: [], styles: []}); }); it('accepts list and slug (non-existent components)', function () { - expect(fn(['a', 'b', 'c'], 'd')).to.deep.equal({scripts: [], styles: []}); - }); - - it('accepts list, empty slug', function () { - var getScripts = sandbox.stub(lib, 'getScripts'); - - sandbox.stub(lib, 'getStyles').returns([]); - getScripts.withArgs('a', state.locals.site).returns(['/e/a']); - getScripts.withArgs('b', state.locals.site).returns(['/e/b']); - getScripts.withArgs('c', state.locals.site).returns(['/e/c', '/e/cc']); - - expect(fn({ _components: ['a', 'b', 'c'], locals: state.locals })).to.deep.equal({scripts: ['/e/a', '/e/b', '/e/c', '/e/cc'], styles: []}); + expect( + fn( + _.merge( + { + _components: ['a', 'b', 'c'] + }, + state + ) + ) + ).to.deep.equal({scripts: [], styles: []}); + }); + + it('retrieves media map based on getScriptFiles and getStyleFiles', function () { + var getScriptFiles = sandbox.stub(lib, 'getScriptFiles'), + expectedScriptFiles = [ + '/e/a', + '/e/b', + '/e/c', + '/e/cc' + ]; + + sandbox.stub(lib, 'getStyleFiles').returns([]); + getScriptFiles.returns(expectedScriptFiles); + + expect( + fn( + _.merge( + state, + { + _components: ['a', 'b', 'c'] + } + ) + ) + ).to.deep.equal({scripts: expectedScriptFiles, styles: []}); }); }); - describe('getStyles', function () { + describe('getStyleFiles', function () { const fn = lib[this.title]; - it('accepts bad component', function () { - files.fileExists.returns(false); - expect(fn('name', state.locals.site)).to.deep.equal([]); - }); - - it('accepts good component', function () { - files.fileExists.onCall(0).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/css/name.css']); - }); - - it('accepts good component with slug (no slug file)', function () { - files.fileExists.onCall(0).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/css/name.css']); - }); - - it('accepts good component with slug (with slug file)', function () { - files.fileExists.onCall(0).returns(true); - files.fileExists.onCall(1).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/css/name.css', '/css/name.foo.css']); - }); + it('utilizes the default MEDIA_DIRECTORY when site has not assetDir defined', function () { + files.fileExists.withArgs(`${process.cwd()}/public/css/a.css`).returns(true); + files.fileExists.withArgs(`${process.cwd()}/public/css/a.${state.locals.site.slug}.css`).returns(true); + expect(fn({ + locals: { + edit: true, + site: { + slug: 'foo' + } + }, + _components: [ + 'a', + 'b' + ] + })).to.deep.equal([ + '/css/a.css', + `/css/a.${state.locals.site.slug}.css` + ]); + }); + + it('utilizes the assetHost when provided', function () { + files.fileExists.withArgs(`${state.locals.site.assetDir}/css/a.css`).returns(true); + files.fileExists.withArgs(`${state.locals.site.assetDir}/css/a.${state.locals.site.slug}.css`).returns(true); + expect(fn({ + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + assetHost: 'https://cache.foo.com' + } + }, + _components: [ + 'a', + 'b' + ] + })).to.deep.equal([ + 'https://cache.foo.com/css/a.css', + `https://cache.foo.com/css/a.${state.locals.site.slug}.css` + ]); + }); + + it('returns no styles when there is a style guide but no _usedVariations object', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [] + }; + + expect(fn(localState)).to.deep.equal([]); + }); + + describe('with no site styleguide (legacy)', function () { + it('handles an empty component list', function () { + expect(fn({ + locals: state.locals, + _components: [] + })).to.deep.equal([]); + }); - it('accepts good component with slug (with slug file) with assetDir', function () { - files.fileExists.withArgs('/foo/css/name.css').returns(true); - files.fileExists.withArgs('/foo/css/name.foo.css').returns(true); + it('handles non-existent components', function () { + expect(fn({ + locals: state.locals, + _components: [ + 'a', + 'b' + ] + })).to.deep.equal([]); + }); - expect(fn('name', state.locals.site)).to.deep.equal(['/css/name.css', '/css/name.foo.css']); + it('handles existent and non-existent components', function () { + files.fileExists.withArgs(`${state.locals.site.assetDir}/css/a.css`).returns(true); + files.fileExists.withArgs(`${state.locals.site.assetDir}/css/a.${state.locals.site.slug}.css`).returns(true); + expect(fn({ + locals: state.locals, + _components: [ + 'a', + 'b' + ] + })).to.deep.equal([ + '/css/a.css', + `/css/a.${state.locals.site.slug}.css` + ]); + }); }); - it('uses the MEDIA_DIRECTORY if one is not defined on the site', function () { - files.fileExists.withArgs(`${process.cwd()}/public/css/name.css`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/css/name.foo.css`).returns(true); - - expect(fn('name', { - slug: 'foo' - })).to.deep.equal(['/css/name.css', '/css/name.foo.css']); - }); + describe('with site styleguide (modern)', function () { + it('handles an empty component list', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [], + _usedVariations: [] + }; - it('if a styleguide is set, base component styles are not grabbed', function () { - files.fileExists.withArgs(`${process.cwd()}/public/css/name.css`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/css/name.bar.css`).returns(true); + expect(fn(localState)).to.deep.equal([]); + }); - expect(fn('name', { - slug: 'foo', - styleguide: 'bar' - })).to.deep.equal(['/css/name.bar.css']); - }); + it('handles an empty _usedVariations', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [ + 'a', + 'b' + ], + _usedVariations: [] + }; - it('if a styleguide is set and there are variations available, grab those variation files', function () { - files.fileExists.withArgs(`${process.cwd()}/public/css/name.bar.css`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/css/name_foo.bar.css`).returns(true); + expect(fn(localState)).to.deep.equal([]); + }); - sandbox.stub(styleguide, 'getVariations', function () { - return { - name: ['name_foo'] + it('it handles non-existent component', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [ + 'a', + 'b' + ], + _usedVariations: [ + 'a_baz', + 'b' + ] }; + + expect(fn(localState)).to.deep.equal([]); }); - expect(fn('name', { - slug: 'foo', - styleguide: 'bar' - })).to.deep.equal(['/css/name.bar.css', '/css/name_foo.bar.css']); - }); + it('defaults to the _default styleguide if the site styleguide file cannot be found', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [ + 'a', + 'b' + ], + _usedVariations: [ + 'a_baz', + 'b' + ] + }; - it('if a styleguide is set and the site styleguide does not have styles, use the default styleguide', function () { - files.fileExists.withArgs(`${process.cwd()}/public/css/name.bar.css`).returns(false); - files.fileExists.withArgs(`${process.cwd()}/public/css/name._default.css`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/css/a_baz._default.css`).returns(true); - sandbox.stub(styleguide, 'getVariations', function () { - return {}; + expect(fn(localState)).to.deep.equal([ + '/css/a_baz._default.css' + ]); }); - expect(fn('name', { - slug: 'foo', - styleguide: 'bar' - })).to.deep.equal(['/css/name._default.css']); - }); + it('prefers the site styleguide file when it can be found', function () { + const localState = { + locals: { + edit: true, + site: { + slug: 'foo', + assetDir: '/foo', + styleguide: 'bar' + } + }, + _components: [ + 'a', + 'b' + ], + _usedVariations: [ + 'a_baz', + 'b' + ] + }; - it('if a variation + styleguide is set and the site styleguide does not have variation styles, use the variation from the default styleguide', function () { - files.fileExists.withArgs(`${process.cwd()}/public/css/name.bar.css`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/css/name_foo.bar.css`).returns(false); - files.fileExists.withArgs(`${process.cwd()}/public/css/name_foo._default.css`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/css/a_baz.${localState.locals.site.styleguide}.css`).returns(true); - sandbox.stub(styleguide, 'getVariations', function () { - return { - name: ['name_foo'] - }; + expect(fn(localState)).to.deep.equal([ + `/css/a_baz.${localState.locals.site.styleguide}.css` + ]); }); - - expect(fn('name', { - slug: 'foo', - styleguide: 'bar' - })).to.deep.equal(['/css/name.bar.css', '/css/name_foo._default.css']); }); }); - describe('getScripts', function () { + describe('getScriptFiles', function () { const fn = lib[this.title]; - it('accepts bad component', function () { - files.fileExists.returns(false); - - expect(fn('name', state.locals.site)).to.deep.equal([]); - }); - - it('accepts good component', function () { - files.fileExists.onCall(0).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js']); - }); - - it('accepts good component with slug (no slug file)', function () { - files.fileExists.onCall(0).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js']); - }); - - it('accepts good component with slug (with slug file)', function () { - files.fileExists.onCall(0).returns(true); - files.fileExists.onCall(1).returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js', '/js/name.foo.js']); - }); - - it('accepts good component and its client.js file', function () { - files.fileExists.withArgs('/foo/js/name.js').returns(true); - files.fileExists.withArgs('/foo/js/name.foo.js').returns(true); - files.fileExists.withArgs('/foo/js/name.client.js').returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js', '/js/name.foo.js', '/js/name.client.js']); - }); - - it('accepts good component with slug (with slug file) with assetDir', function () { - files.fileExists.withArgs('/foo/js/name.js').returns(true); - files.fileExists.withArgs('/foo/js/name.foo.js').returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js', '/js/name.foo.js']); - }); - - it('accepts good component with slug (with slug file) with assetDir', function () { - files.fileExists.withArgs('/foo/js/name.js').returns(true); - files.fileExists.withArgs('/foo/js/name.foo.js').returns(true); - - expect(fn('name', state.locals.site)).to.deep.equal(['/js/name.js', '/js/name.foo.js']); + it('handles an empty component list', function () { + const localState = { + locals: { + site: { + slug: 'foo', + assetDir: '/foo' + } + }, + _components: [] + }; + + expect(fn(localState)).to.deep.equal([]); + }); + + it('handles non-existent components', function () { + const localState = { + locals: { + site: { + slug: 'foo', + assetDir: '/foo' + } + }, + _components: [ + 'a' + ] + }; + + expect(fn(localState)).to.deep.equal([]); + }); + + it('handles a mixture non-existent components and existent components', function () { + const localState = { + locals: { + site: { + slug: 'foo', + assetDir: '/foo' + } + }, + _components: [ + 'a', + 'b' + ] + }; + + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.js`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.${localState.locals.site.slug}.js`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.client.js`).returns(true); + + expect(fn(localState)).to.deep.equal([ + '/js/a.js', + `/js/a.${localState.locals.site.slug}.js`, + '/js/a.client.js' + ]); }); it('uses the MEDIA_DIRECTORY if one is not defined on the site', function () { - files.fileExists.withArgs(`${process.cwd()}/public/js/name.js`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/js/name.foo.js`).returns(true); - - expect(fn('name', { - slug: 'foo' - })).to.deep.equal(['/js/name.js', '/js/name.foo.js']); + const localState = { + locals: { + site: { + slug: 'foo' + } + }, + _components: [ + 'a', + 'b' + ] + }; + + files.fileExists.withArgs(`${process.cwd()}/public/js/a.js`).returns(true); + files.fileExists.withArgs(`${process.cwd()}/public/js/a.${localState.locals.site.slug}.js`).returns(true); + files.fileExists.withArgs(`${process.cwd()}/public/js/a.client.js`).returns(true); + + expect(fn(localState)).to.deep.equal([ + '/js/a.js', + `/js/a.${localState.locals.site.slug}.js`, + '/js/a.client.js' + ]); }); it('uses the assetHost value if one is passed in', function () { - files.fileExists.withArgs(`${process.cwd()}/public/js/name.js`).returns(true); - files.fileExists.withArgs(`${process.cwd()}/public/js/name.foo.js`).returns(true); - - expect(fn('name', { - slug: 'foo', - assetHost: 'https://cache.foo.com' - })).to.deep.equal(['https://cache.foo.com/js/name.js', 'https://cache.foo.com/js/name.foo.js']); + const localState = { + locals: { + site: { + slug: 'foo', + assetDir: '/foo', + assetHost: 'https://cache.foo.com' + } + }, + _components: [ + 'a', + 'b' + ] + }; + + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.js`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.${localState.locals.site.slug}.js`).returns(true); + files.fileExists.withArgs(`${localState.locals.site.assetDir}/js/a.client.js`).returns(true); + + expect(fn(localState)).to.deep.equal([ + `${localState.locals.site.assetHost}/js/a.js`, + `${localState.locals.site.assetHost}/js/a.${localState.locals.site.slug}.js`, + `${localState.locals.site.assetHost}/js/a.client.js` + ]); + }); + + it('makes 3 file exists calls for every component in the component list', function () { + const localState = { + locals: { + site: { + slug: 'foo', + assetDir: '/foo' + } + }, + _components: [ + 'a', + 'b' + ] + }; + + fn(localState); + expect(files.fileExists.args.map(function (argv) { return argv[0]; })).to.deep.equal([ + `${localState.locals.site.assetDir}/js/a.js`, + `${localState.locals.site.assetDir}/js/a.${localState.locals.site.slug}.js`, + `${localState.locals.site.assetDir}/js/a.client.js`, + `${localState.locals.site.assetDir}/js/b.js`, + `${localState.locals.site.assetDir}/js/b.${localState.locals.site.slug}.js`, + `${localState.locals.site.assetDir}/js/b.client.js` + ]); }); }); @@ -321,7 +527,7 @@ describe(_.startCase(filename), function () { }); it('if in view mode, just inlines immediately', function () { - return fn({ locals: { edit: false } })(basicHtml).then((html) => { + return fn({ locals: { edit: false, site: {} }, _components: [] })(basicHtml).then((html) => { expect(html).to.deep.equal(basicHtml); }); }); diff --git a/lib/render.js b/lib/render.js index b7d31ee..272b862 100644 --- a/lib/render.js +++ b/lib/render.js @@ -44,7 +44,7 @@ function makeHtml(state) { const template = clayUtils.getComponentName(state._layoutRef || state._self), rootPartial = hbs.partials[template]; - styleguide.setDefaultVariations(_data, state._componentVariations); + styleguide.setDefaultVariations(_data, state); if (!rootPartial) { throw new Error(`Missing template for ${template}`); diff --git a/lib/styleguide.js b/lib/styleguide.js index 19a84df..b109cd9 100644 --- a/lib/styleguide.js +++ b/lib/styleguide.js @@ -37,7 +37,7 @@ function findVariationFiles(styleguide) { * component and its variations */ function getVariations(styleguide = '_default') { - const foundVariations = styleguide !== '_default' ? findVariationFiles(styleguide).concat(findVariationFiles('_default')) : findVariationFiles('_default'), + const foundVariations = styleguide !== '_default' ? _.uniq(findVariationFiles(styleguide).concat(findVariationFiles('_default'))) : findVariationFiles('_default'), componentVariations = {}; if (foundVariations.length) { @@ -55,9 +55,15 @@ function getVariations(styleguide = '_default') { * Goes through page data and sets a default for components * * @param {object} pageData -* @param {object} variations - all components with variations, generated by getVariations +* @param {object} state w/ _componentVariations */ -function setDefaultVariations(pageData, variations) { +function setDefaultVariations(pageData, state) { + const variations = state._componentVariations, + layoutName = clayUtils.getComponentName(state._layoutRef), + usedVariations = { + [layoutName]: true + }; + traverse(pageData).forEach(function (val) { let componentName, componentVariations; @@ -72,12 +78,17 @@ function setDefaultVariations(pageData, variations) { // component has a variation set, but it doesn't exist in the site's styleguide or the default styleguide! // render the component with the default variation _.set(val, 'componentVariation', componentName); + usedVariations[`${componentName}`] = true; } else if (!val.componentVariation) { // component has no variation set! // render the component with the default variation _.set(val, 'componentVariation', componentName); + usedVariations[`${componentName}`] = true; + } else { + usedVariations[`${val.componentVariation}`] = true; } }); + state._usedVariations = Object.keys(usedVariations); } exports.getVariations = _.memoize(getVariations); diff --git a/lib/styleguide.test.js b/lib/styleguide.test.js index 304bac4..9b5a3fa 100644 --- a/lib/styleguide.test.js +++ b/lib/styleguide.test.js @@ -26,6 +26,7 @@ describe(_.startCase(filename), function () { ], defaultMockData = [ 'blockquote.css', + 'blockquote_red.css', 'pull-quote.css', 'pull-quote_large.css' ]; @@ -57,7 +58,8 @@ describe(_.startCase(filename), function () { it('gets default variations', function () { var expected = { - 'pull-quote': [ 'pull-quote_large' ] + 'pull-quote': [ 'pull-quote_large' ], + blockquote: [ 'blockquote_red' ] }; expect(lib.getVariations('_default')).to.deep.equal(expected); @@ -121,11 +123,26 @@ describe(_.startCase(filename), function () { }, ] }, - variations = lib.getVariations('vulture'); + expectedUsedVariations = [ + 'layout', + 'blockquote_red', + 'blockquote', + 'clay-paragraph', + 'article-sidebar', + 'video' + ], + state = { + _layoutRef: 'www.vulture.com/_components/layout/instances/article', + _componentVariations: lib.getVariations('vulture') + }; - lib.setDefaultVariations(testData, variations); + lib.setDefaultVariations( + testData, + state + ); expect(testData).to.deep.equal(expectedData); + expect(state._usedVariations).to.deep.equal(expectedUsedVariations); }); it('sets default variation if specified variation does not exist', function () { @@ -144,17 +161,25 @@ describe(_.startCase(filename), function () { componentVariation: 'blockquote' } ] + }, + state = { + _layoutRef: 'www.vulture.com/_components/layout/instances/article', + _componentVariations: {} }; - lib.setDefaultVariations(testData, {}); + lib.setDefaultVariations(testData, state); expect(testData).to.deep.equal(expectedData); }); it('do not change data if there are no components in the page data', function () { var testData = ['Steve Rogers', 'Tony Stark', 'Natasha Romanov', 'Clint Barton', 'Wanda Maximoff'], - variations = lib.getVariations('vulture'); + variations = lib.getVariations('vulture'), + state = { + _layoutRef: 'www.vulture.com/_components/layout/instances/article', + _componentVariations: variations + }; - lib.setDefaultVariations(testData, variations); + lib.setDefaultVariations(testData, state); expect(testData).to.equal(testData); }); @@ -170,9 +195,13 @@ describe(_.startCase(filename), function () { _ref: 'nymag.com/daily/intelligencer/_components/clay-paragraph/instances/cjeq5662h001b3i61rr8fffu1@published', } ], - variations = lib.getVariations('di'); + variations = lib.getVariations('di'), + state = { + _layoutRef: 'nymag.com/daily/intelligencer/_components/layout/instances/article', + _componentVariations: variations + }; - lib.setDefaultVariations(testData, variations); + lib.setDefaultVariations(testData, state); expect(testData).to.equal(testData); });