Skip to content
8 changes: 6 additions & 2 deletions packages/core/src/lib/loadPattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 +
'.'
);
Expand All @@ -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. '
Expand Down
71 changes: 54 additions & 17 deletions packages/core/src/lib/object_factory.js
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 || {};
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -206,15 +243,15 @@ 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
// parameters that replace the positional parameters that the Pattern
// 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 = {
Expand Down
109 changes: 109 additions & 0 deletions packages/core/test/object_factory_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
) {
Expand Down Expand Up @@ -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
) {
Expand Down Expand Up @@ -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();
});