diff --git a/packages/core/src/lib/loadPattern.js b/packages/core/src/lib/loadPattern.js index 6eae3843e..3cf43a7b1 100644 --- a/packages/core/src/lib/loadPattern.js +++ b/packages/core/src/lib/loadPattern.js @@ -23,13 +23,13 @@ let fs = require('fs-extra'); //eslint-disable-line prefer-const // all its associated files, and records it in patternlab.patterns[] module.exports = function(relPath, patternlab) { const relativeDepth = (relPath.match(/\w(?=\\)|\w(?=\/)/g) || []).length; - if (relativeDepth > 2) { + if (relativeDepth > 3) { logger.warning(''); logger.warning('Warning:'); logger.warning( 'A pattern file: ' + relPath + - ' was found greater than 2 levels deep from ' + + ' was found greater than 3 levels deep from ' + patternlab.config.paths.source.patterns + '.' ); @@ -39,6 +39,10 @@ module.exports = function(relPath, patternlab) { logger.warning( '[patternType]/[patternSubtype]/[patternName].[patternExtension]' ); + logger.warning('or'); + logger.warning( + '[patternType]/[patternSubtype]/[patternName]/[patternName].[patternExtension]' + ); logger.warning(''); logger.warning( 'While Pattern Lab may still function, assets may 404 and frontend links may break. Consider yourself warned. ' diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 0c3ffe5d2..8135e3988 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -1,7 +1,6 @@ 'use strict'; const patternEngines = require('./pattern_engines'); const path = require('path'); -const extend = require('util')._extend; // patternPrefixMatcher is intended to match the leading maybe-underscore, // zero or more digits, and maybe-dash at the beginning of a pattern file name we can hack them @@ -22,14 +21,37 @@ const Pattern = function(relPath, data, patternlab) { * @param {patternlab} rendered html files for the pattern */ const pathObj = path.parse(path.normalize(relPath)); + const info = {}; + // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + info.hasDir = + path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === + pathObj.name.replace(patternPrefixMatcher, '') || + path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === + pathObj.name.split('~')[0].replace(patternPrefixMatcher, ''); + + info.dir = info.hasDir ? pathObj.dir.split(path.sep).pop() : ''; + info.dirLevel = pathObj.dir.split(path.sep).length; + this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' this.fileName = pathObj.name; // '00-colors' this.subdir = pathObj.dir; // '00-atoms/00-global' this.fileExtension = pathObj.ext; // '.mustache' // this is the unique name, subDir + fileName (sans extension) - this.name = - this.subdir.replace(path.sep, '-') + '-' + this.fileName.replace('~', '-'); // '00-atoms-00-global-00-colors' + this.name = ''; + if (info.hasDir) { + let variant = ''; + + if (this.fileName.indexOf('~') !== -1) { + variant = '-' + this.fileName.split('~')[1]; + } + this.name = this.subdir.replace(/[\/\\]/g, '-') + variant; + } else { + this.name = + this.subdir.replace(/[\/\\]/g, '-') + + '-' + + this.fileName.replace('~', '-'); // '00-atoms-00-global-00-colors' + } // the JSON used to render values in the pattern this.jsonFileData = data || {}; @@ -53,24 +75,24 @@ const Pattern = function(relPath, data, patternlab) { }, '') .trim(); //this is the display name for the ui. strip numeric + hyphen prefixes - // the top-level pattern group this pattern belongs to. 'atoms' - this.patternGroup = this.subdir - .split(path.sep)[0] - .replace(patternPrefixMatcher, ''); - //00-atoms if needed - this.patternType = this.subdir.split(path.sep)[0]; + this.patternType = this.getDirLevel(0, info); - // the sub-group this pattern belongs to. - this.patternSubGroup = path - .basename(this.subdir) - .replace(patternPrefixMatcher, ''); // 'global' + // the top-level pattern group this pattern belongs to. 'atoms' + this.patternGroup = this.patternType.replace(patternPrefixMatcher, ''); //00-colors if needed - this.patternSubType = path.basename(this.subdir); + this.patternSubType = this.getDirLevel(1, info); + + // the sub-group this pattern belongs to. + this.patternSubGroup = this.patternSubType.replace(patternPrefixMatcher, ''); // 'global' // the joined pattern group and subgroup directory - this.flatPatternPath = this.subdir.replace(/[\/\\]/g, '-'); // '00-atoms-00-global' + this.flatPatternPath = info.hasDir + ? this.subdir + .replace(/[/\\]/g, '-') + .replace(new RegExp('-' + info.dir + '$'), '') + : this.subdir.replace(/[\/\\]/g, '-'); // '00-atoms-00-global' // calculated path from the root of the public directory to the generated // (rendered!) html file for this pattern, to be shown in the iframe @@ -189,6 +211,21 @@ Pattern.prototype = { findPartial: function(partialString) { return this.engine.findPartial(partialString); }, + + getDirLevel: function(level, info) { + const items = this.subdir.split(path.sep); + if (info.hasDir) { + items.pop(); + } + + if (items[level]) { + return items[level]; + } else if (items[level - 1]) { + return items[level - 1]; + } else { + return ''; + } + }, }; // Pattern static methods @@ -206,7 +243,7 @@ Pattern.createEmpty = function(customProps, patternlab) { } const pattern = new Pattern(relPath, null, patternlab); - return extend(pattern, customProps); + return Object.assign(pattern, customProps); }; // factory: creates an Pattern object on-demand from a hash; the hash accepts @@ -214,7 +251,7 @@ Pattern.createEmpty = function(customProps, patternlab) { // constructor takes. Pattern.create = function(relPath, data, customProps, patternlab) { const newPattern = new Pattern(relPath || '', data || null, patternlab); - return extend(newPattern, customProps); + return Object.assign(newPattern, customProps); }; const CompileState = { diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index 463dce978..166416e27 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -63,6 +63,66 @@ tap.test('test Pattern initializes correctly', function(test) { test.end(); }); +tap.test( + 'test Pattern initializes correctly with pattern in sepatated directory', + function(test) { + var p = new Pattern('00-atoms/00-global/00-colors/colors.mustache', { + d: 123, + }); + test.equals( + p.relPath, + '00-atoms' + + path.sep + + '00-global' + + path.sep + + '00-colors' + + path.sep + + 'colors.mustache' + ); + test.equals(p.name, '00-atoms-00-global-00-colors'); + test.equals( + p.subdir, + '00-atoms' + path.sep + '00-global' + path.sep + '00-colors' + ); + test.equals(p.fileName, 'colors'); + test.equals(p.fileExtension, '.mustache'); + test.equals(p.jsonFileData.d, 123); + test.equals(p.patternBaseName, 'colors'); + test.equals(p.patternName, 'Colors'); + test.equals( + p.getPatternLink(pl), + '00-atoms-00-global-00-colors' + + path.sep + + '00-atoms-00-global-00-colors.rendered.html' + ); + test.equals(p.patternGroup, 'atoms'); + test.equals(p.patternSubGroup, 'global'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + test.equals(p.patternPartial, 'atoms-colors'); + test.equals(p.template, ''); + test.equals(p.patternPartialCode, ''); + test.equals(p.lineage.length, 0); + test.equals(p.lineageIndex.length, 0); + test.equals(p.lineageR.length, 0); + test.equals(p.lineageRIndex.length, 0); + test.equals(p.patternState, ''); + test.end(); + } +); + +tap.test('test Pattern name for variants correctly initialzed', function(test) { + var p1 = new Pattern('00-atoms/00-global/00-colors/colors~variant.mustache', { + d: 123, + }); + var p2 = new Pattern( + '00-atoms/00-global/00-colors/colors~variant-minus.json', + { d: 123 } + ); + test.equals(p1.name, '00-atoms-00-global-00-colors-variant'); + test.equals(p2.name, '00-atoms-00-global-00-colors-variant-minus'); + test.end(); +}); + tap.test('test Pattern with one-directory subdir works as expected', function( test ) { @@ -118,6 +178,49 @@ tap.test('test Pattern capitalizes patternDisplayName correctly', function( test.end(); }); +tap.test('test Pattern get dir level no sepatated pattern directory', function( + test +) { + var p = new Pattern('00-atoms/00-global/00-colors-alt.mustache', { d: 123 }); + console.log(p); + test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 2 }), '00-atoms'); + test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 2 }), '00-global'); + test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 2 }), ''); + var p = new Pattern('00-atoms/00-colors-alt.mustache', { d: 123 }); + test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 1 }), '00-atoms'); + test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 1 }), '00-atoms'); + test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 1 }), ''); + var p = new Pattern('00-colors-alt.mustache', { d: 123 }); + test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 0 }), ''); + test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 0 }), ''); + test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 0 }), ''); + test.end(); +}); + +tap.test( + 'test Pattern get dir level with sepatated pattern directory', + function(test) { + var p = new Pattern( + '00-atoms/00-global/00-colors-alt/colors-alt.mustache', + { d: 123 } + ); + test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 3 }), '00-atoms'); + test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 3 }), '00-global'); + test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 3 }), ''); + var p = new Pattern('00-atoms/00-colors-alt/colors-alt.mustache', { + d: 123, + }); + test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 2 }), '00-atoms'); + test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 2 }), '00-atoms'); + test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 2 }), ''); + var p = new Pattern('00-colors-alt/colors-alt.mustache', { d: 123 }); + test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 1 }), ''); + test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 1 }), ''); + test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 1 }), ''); + test.end(); + } +); + tap.test('The forms of Pattern.getPatternLink() work as expected', function( test ) { @@ -146,5 +249,11 @@ tap.test('The forms of Pattern.getPatternLink() work as expected', function( path.sep + '00-atoms-00-global-00-colors.markup-only.html' ); + test.equals( + p.getPatternLink(pl, 'custom', '.custom-extension'), + '00-atoms-00-global-00-colors' + + path.sep + + '00-atoms-00-global-00-colors.custom-extension' + ); test.end(); });