From b30ed5c30b9a63eeffeae6b9a527ccc07ac8fecb Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Thu, 21 Feb 2019 11:58:48 +0100 Subject: [PATCH 1/7] Added separated pattern-folder support Added the functionality to separate the patterns from each other by adding the support for a capsulation folder by pattern. Also added tests. --- packages/core/src/lib/loadPattern.js | 8 +- packages/core/src/lib/object_factory.js | 71 ++++++++++---- packages/core/test/object_factory_tests.js | 109 +++++++++++++++++++++ 3 files changed, 168 insertions(+), 20 deletions(-) diff --git a/packages/core/src/lib/loadPattern.js b/packages/core/src/lib/loadPattern.js index 6eae3843e..0817032e7 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]/[patternNameFolder]/[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..c0e42f3b2 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,34 @@ const Pattern = function(relPath, data, patternlab) { * @param {patternlab} rendered html files for the pattern */ const pathObj = path.parse(path.normalize(relPath)); + const info = {}; + // colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + info.hasDir = + pathObj.dir.indexOf(pathObj.name) !== -1 || + pathObj.dir.indexOf(pathObj.name.split('~')[0]) !== -1; + 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,30 +72,30 @@ 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('-' + 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 this.patternLink = this.patternSectionSubtype ? `$${this.name}/index.html` - : patternlab ? this.getPatternLink(patternlab, 'rendered') : null; + : patternlab // eslint-disable-next-line prettier/prettier + ? this.getPatternLink(patternlab, 'rendered') // eslint-disable-next-line prettier/prettier + : null; // The canonical "key" by which this pattern is known. This is the callable // name of the pattern. UPDATE: this.key is now known as this.patternPartial @@ -189,6 +208,22 @@ Pattern.prototype = { findPartial: function(partialString) { return this.engine.findPartial(partialString); }, + + getDirLevel: function(level, info) { + // eslint-disable-next-line prefer-const + let 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 +241,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 +249,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(); }); From 263ee423112d55900525dec355573746bdb9fb08 Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Thu, 7 Mar 2019 11:06:32 +0100 Subject: [PATCH 2/7] Small fix for double nested folders Only replace the last occurence of the nested pattern folder. like grid-system-grid to grid-system as main folder. --- packages/core/src/lib/object_factory.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index c0e42f3b2..0cc6278a1 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -86,7 +86,9 @@ const Pattern = function(relPath, data, patternlab) { // the joined pattern group and subgroup directory this.flatPatternPath = info.hasDir - ? this.subdir.replace(/[\/\\]/g, '-').replace('-' + info.dir, '') + ? 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 From b18399c182d6ebd504c726ca18a2c5b8f79644e6 Mon Sep 17 00:00:00 2001 From: Josef Engelfrost Date: Mon, 11 Mar 2019 08:55:13 +0100 Subject: [PATCH 3/7] Update loadPattern.js from the suggestion of @engelfrost Co-Authored-By: JosefBredereck --- packages/core/src/lib/loadPattern.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/loadPattern.js b/packages/core/src/lib/loadPattern.js index 0817032e7..3cf43a7b1 100644 --- a/packages/core/src/lib/loadPattern.js +++ b/packages/core/src/lib/loadPattern.js @@ -41,7 +41,7 @@ module.exports = function(relPath, patternlab) { ); logger.warning('or'); logger.warning( - '[patternType]/[patternSubtype]/[patternNameFolder]/[patternName].[patternExtension]' + '[patternType]/[patternSubtype]/[patternName]/[patternName].[patternExtension]' ); logger.warning(''); logger.warning( From 6a2a467b427cd08c3ce3851de206a2362fafdef9 Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Mon, 11 Mar 2019 09:04:56 +0100 Subject: [PATCH 4/7] The separated pattern folder name must be the pattern name Like @engelfrost suggested it should be the same name, so that there is no error with the pattern group and subgroup names. --- packages/core/src/lib/object_factory.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 0cc6278a1..8c2b28e87 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -22,10 +22,11 @@ const Pattern = function(relPath, data, patternlab) { */ const pathObj = path.parse(path.normalize(relPath)); const info = {}; - // colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors info.hasDir = - pathObj.dir.indexOf(pathObj.name) !== -1 || - pathObj.dir.indexOf(pathObj.name.split('~')[0]) !== -1; + path.basename(pathObj.dir) === pathObj.name || + path.basename(pathObj.dir) === pathObj.name.split('~')[0]; + info.dir = info.hasDir ? pathObj.dir.split(path.sep).pop() : ''; info.dirLevel = pathObj.dir.split(path.sep).length; From 0907bab23dcc4a3c9380853f112d11e30305b3cb Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Mon, 11 Mar 2019 16:59:20 +0100 Subject: [PATCH 5/7] Updated tests since pattern folder name has to be the pattern name --- packages/core/test/object_factory_tests.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index 166416e27..b8bfe7fba 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -66,7 +66,7 @@ tap.test('test Pattern initializes correctly', function(test) { 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', { + var p = new Pattern('00-atoms/00-global/00-colors/00-colors.mustache', { d: 123, }); test.equals( @@ -77,14 +77,14 @@ tap.test( path.sep + '00-colors' + path.sep + - 'colors.mustache' + '00-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.fileName, '00-colors'); test.equals(p.fileExtension, '.mustache'); test.equals(p.jsonFileData.d, 123); test.equals(p.patternBaseName, 'colors'); @@ -111,11 +111,14 @@ tap.test( ); 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 p1 = new Pattern( + '00-atoms/00-global/00-colors/00-colors~variant.mustache', + { + d: 123, + } + ); var p2 = new Pattern( - '00-atoms/00-global/00-colors/colors~variant-minus.json', + '00-atoms/00-global/00-colors/00-colors~variant-minus.json', { d: 123 } ); test.equals(p1.name, '00-atoms-00-global-00-colors-variant'); From 8ffce153bd74465168ed6801c3905c78cbad0b32 Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Tue, 12 Mar 2019 09:08:56 +0100 Subject: [PATCH 6/7] Removed not needed eslint ignore line --- packages/core/src/lib/object_factory.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 8c2b28e87..96c139adb 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -213,8 +213,7 @@ Pattern.prototype = { }, getDirLevel: function(level, info) { - // eslint-disable-next-line prefer-const - let items = this.subdir.split(path.sep); + const items = this.subdir.split(path.sep); if (info.hasDir) { items.pop(); } From 2225f99716a017677cb7195013aa66496c771651 Mon Sep 17 00:00:00 2001 From: Josef Bredereck Date: Tue, 19 Mar 2019 10:27:46 +0100 Subject: [PATCH 7/7] Remove eslint-disable and made changed pattern name and dir behavior It is now possible to set up patterns like `../00-colors/00-colors.(extension)` or `../00-colors/colors.(extension)` the match will be the pattern name without the prefix numbers. --- packages/core/src/lib/object_factory.js | 10 +++++----- packages/core/test/object_factory_tests.js | 17 +++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 96c139adb..8135e3988 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -24,8 +24,10 @@ const Pattern = function(relPath, data, patternlab) { const info = {}; // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors info.hasDir = - path.basename(pathObj.dir) === pathObj.name || - path.basename(pathObj.dir) === pathObj.name.split('~')[0]; + 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; @@ -96,9 +98,7 @@ const Pattern = function(relPath, data, patternlab) { // (rendered!) html file for this pattern, to be shown in the iframe this.patternLink = this.patternSectionSubtype ? `$${this.name}/index.html` - : patternlab // eslint-disable-next-line prettier/prettier - ? this.getPatternLink(patternlab, 'rendered') // eslint-disable-next-line prettier/prettier - : null; + : patternlab ? this.getPatternLink(patternlab, 'rendered') : null; // The canonical "key" by which this pattern is known. This is the callable // name of the pattern. UPDATE: this.key is now known as this.patternPartial diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index b8bfe7fba..166416e27 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -66,7 +66,7 @@ tap.test('test Pattern initializes correctly', function(test) { tap.test( 'test Pattern initializes correctly with pattern in sepatated directory', function(test) { - var p = new Pattern('00-atoms/00-global/00-colors/00-colors.mustache', { + var p = new Pattern('00-atoms/00-global/00-colors/colors.mustache', { d: 123, }); test.equals( @@ -77,14 +77,14 @@ tap.test( path.sep + '00-colors' + path.sep + - '00-colors.mustache' + '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, '00-colors'); + test.equals(p.fileName, 'colors'); test.equals(p.fileExtension, '.mustache'); test.equals(p.jsonFileData.d, 123); test.equals(p.patternBaseName, 'colors'); @@ -111,14 +111,11 @@ tap.test( ); tap.test('test Pattern name for variants correctly initialzed', function(test) { - var p1 = new Pattern( - '00-atoms/00-global/00-colors/00-colors~variant.mustache', - { - d: 123, - } - ); + 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/00-colors~variant-minus.json', + '00-atoms/00-global/00-colors/colors~variant-minus.json', { d: 123 } ); test.equals(p1.name, '00-atoms-00-global-00-colors-variant');