Skip to content

Commit ec3abdc

Browse files
committed
Merge branch 'dev-3.0' into asset-copy
# Conflicts: # package.json
2 parents 4e898c6 + 5690a63 commit ec3abdc

21 files changed

+4544
-51
lines changed

.github/CONTRIBUTING.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
1-
# Contributing to Patternlab Node
1+
# Contributing to Pattern Lab Node
22
If you'd like to contribute to Pattern Lab Node, please do so! There is always a lot of ground to cover and something for your wheelhouse.
33

44
No pull request is too small. Check out any [up for grabs issues](https://github.com/pattern-lab/patternlab-node/labels/up%20for%20grabs) as a good way to get your feet wet, or add some more unit tests.
55

6+
## Developing Locally
7+
8+
The best way to make changes to the Pattern Lab Node core and test them is through your existing edition.
9+
10+
* Fork this repository on Github.
11+
* Create a new branch in your fork and push your changes in that fork.
12+
* `npm install`
13+
* `npm link`
14+
* `cd /path/to/your/edition`
15+
* `npm link patternlab-node`
16+
617
## Guidelines
7-
1. Please keep your pull requests concise and limited to **ONE** substantive change at a time. This makes reviewing and testing so much easier.
8-
2. _ALWAYS_ submit pull requests against the [dev branch](https://github.com/pattern-lab/patternlab-node/tree/dev). If this does not occur, I will first, try to redirect you gently, second, port over your contribution manually if time allows, and/or third, close your pull request. If you have a major feature to stabilize over time, talk to @bmuenzenmeyer about making a dedicated `feature-branch`
9-
3. If you can, add some unit tests using the existing patterns in the `./test` directory
1018

11-
##Coding style
19+
* _ALWAYS_ submit pull requests against the [dev branch](https://github.com/pattern-lab/patternlab-node/tree/dev). If this does not occur, I will first, try to redirect you gently, second, port over your contribution manually if time allows, and/or third, close your pull request. If you have a major feature to stabilize over time, talk to @bmuenzenmeyer via an issue about making a dedicated `feature-branch`
20+
* Please keep your pull requests concise and limited to **ONE** substantive change at a time. This makes reviewing and testing so much easier.
21+
* Commits should reference the issue you are adressing. For any Pull Request that you send, use the template provided.
22+
* If you can, add some unit tests using the existing patterns in the `./test` directory
23+
* Large enhancements should begin with opening an issue. This will result in a more systematic way for us to review your contribution and determine if a [specifcation discussion](https://github.com/pattern-lab/the-spec/issues) needs to occur.
24+
25+
## Coding style
1226
Two files combine within the project to define and maintain our coding style.
1327

1428
* The `.editorconfig` controls spaces / tabs within supported editors. Check out their [site](http://editorconfig.org/).

.github/stale.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Number of days of inactivity before an issue becomes stale
2+
daysUntilStale: 60
3+
# Number of days of inactivity before a stale issue is closed
4+
daysUntilClose: 7
5+
# Issues with these labels will never be considered stale
6+
exemptLabels:
7+
- staged for next release
8+
- pinned
9+
# Label to use when marking an issue as stale
10+
staleLabel: needs response
11+
# Comment to post when marking an issue as stale. Set to `false` to disable
12+
markComment: >
13+
This issue has been automatically marked as stale because it has not had
14+
recent activity. It will be closed if no further activity occurs. Thank you
15+
for your contributions.
16+
# Comment to post when closing a stale issue. Set to `false` to disable
17+
closeComment: false

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ This repository contains the core functionality for Pattern Lab Node. Pattern La
1010

1111
## Support for Pattern Lab Node
1212

13-
Pattern Lab Node wouldn't be what it is today without the support of the community. It will always be free and open source. Continued development is made possible in part from the support of [these wonderful project supporters](https://github.com/pattern-lab/patternlab-node/wiki/Thanks). If you want to learn more about supporting the project, visit the [Pattern Lab Node Patreon page](https://www.patreon.com/patternlab).
13+
Pattern Lab Node wouldn't be what it is today without the support of the community. It will always be free and open source. Continued development is made possible in part from the support of [these wonderful project supporters](https://github.com/pattern-lab/patternlab-node/wiki/Thanks). If you want to learn more about supporting the project, visit the [Pattern Lab Node Patreon page](https://www.patreon.com/patternlab).
1414

15-
**:100: Thanks for support from the following:**
15+
**:100: Thanks for support from the following:**
1616

1717
* **[Brad Frost](http://bradfrost.com/)**
1818
* [Marcos Peebles](https://twitter.com/marcospeebles)
1919
* [Susan Simkins](https://twitter.com/susanmsimkins)
20+
* [Wilfred Nas](https://twitter.com/wnas)
2021

2122
## Installation
2223

core/lib/data_loader.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"use strict";
2+
3+
const glob = require('glob'),
4+
_ = require('lodash'),
5+
path = require('path'),
6+
yaml = require('js-yaml');
7+
8+
/**
9+
* Loads a single config file, in yaml/json format.
10+
*
11+
* @param dataFilesPath - leave off the file extension.
12+
* @param fsDep
13+
* @returns {*}
14+
*/
15+
function loadFile(dataFilesPath, fsDep) {
16+
const dataFilesFullPath = dataFilesPath + '{.,[!-]*.}{json,yml,yaml}';
17+
18+
if (dataFilesPath) {
19+
const dataFiles = glob.sync(dataFilesFullPath),
20+
dataFile = _.head(dataFiles);
21+
22+
if (dataFile && fsDep.existsSync(path.resolve(dataFile))) {
23+
return yaml.safeLoad(fsDep.readFileSync(path.resolve(dataFile), 'utf8'));
24+
}
25+
}
26+
27+
return null;
28+
}
29+
30+
/**
31+
* Loads a set of config files from a folder, in yaml/json format.
32+
*
33+
* @param dataFilesPath - leave off the file extension
34+
* @param excludeFileNames - leave off the file extension
35+
* @param fsDep
36+
* @returns Object, with merged data files, empty object if no files.
37+
*/
38+
function loadDataFromFolder(dataFilesPath, excludeFileNames, fsDep) {
39+
const dataFilesFullPath = dataFilesPath + '*.{json,yml,yaml}',
40+
excludeFullPath = dataFilesPath + excludeFileNames + '.{json,yml,yaml}';
41+
42+
const globOptions = {};
43+
if (excludeFileNames) {
44+
globOptions.ignore = [excludeFullPath];
45+
}
46+
47+
const dataFiles = glob.sync(dataFilesFullPath, globOptions);
48+
let mergeObject = {};
49+
50+
dataFiles.forEach(function (filePath) {
51+
const jsonData = yaml.safeLoad(fsDep.readFileSync(path.resolve(filePath), 'utf8'));
52+
mergeObject = _.merge(mergeObject, jsonData);
53+
});
54+
55+
return mergeObject;
56+
}
57+
58+
module.exports = function configFileLoader() {
59+
return {
60+
loadDataFromFile: loadFile,
61+
loadDataFromFolder: loadDataFromFolder
62+
};
63+
};

core/lib/object_factory.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const Pattern = function (relPath, data, patternlab) {
6666

6767
// Let's calculate the verbose name ahead of time! We don't use path.sep here
6868
// on purpose. This isn't a file name!
69-
this.verbosePartial = this.subdir + '/' + this.fileName;
69+
this.verbosePartial = this.subdir.split(path.sep).join('/') + '/' + this.fileName;
7070

7171
this.isPattern = true;
7272
this.isFlatPattern = this.patternGroup === this.patternSubGroup;

core/lib/parameter_hunter.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ const parameter_hunter = function () {
4949
* * Return paramStringWellFormed.
5050
*
5151
* @param {string} pString
52+
* @param {object} patternlab
5253
* @returns {string} paramStringWellFormed
5354
*/
54-
function paramToJson(pString) {
55+
function paramToJson(pString, patternlab) {
5556
let colonPos = -1;
5657
const keys = [];
5758
let paramString = pString; // to not reassign param
@@ -61,6 +62,17 @@ const parameter_hunter = function () {
6162
const values = [];
6263
let wrapper;
6364

65+
// attempt to parse the data in case it is already well formed JSON
66+
try {
67+
paramStringWellFormed = JSON.stringify(JSON.parse(pString));
68+
return paramStringWellFormed;
69+
} catch (err) {
70+
//todo this might be a good candidate for a different log level, should we implement that someday
71+
if (patternlab.config.debug) {
72+
console.log(`Not valid JSON found for passed pattern parameter ${pString} will attempt to parse manually...`);
73+
}
74+
}
75+
6476
//replace all escaped double-quotes with escaped unicode
6577
paramString = paramString.replace(/\\"/g, '\\u0022');
6678

@@ -252,7 +264,7 @@ const parameter_hunter = function () {
252264
const leftParen = pMatch.indexOf('(');
253265
const rightParen = pMatch.lastIndexOf(')');
254266
const paramString = '{' + pMatch.substring(leftParen + 1, rightParen) + '}';
255-
const paramStringWellFormed = paramToJson(paramString);
267+
const paramStringWellFormed = paramToJson(paramString, patternlab);
256268

257269
let paramData = {};
258270
let globalData = {};
@@ -267,6 +279,10 @@ const parameter_hunter = function () {
267279
console.log(err);
268280
}
269281

282+
// resolve any pattern links that might be present
283+
paramData = pattern_assembler.parse_data_links_specific(patternlab, paramData, pattern.patternPartial);
284+
285+
//combine all data: GLOBAL DATA => PATTERN.JSON DATA => PARAMETER DATA
270286
let allData = _.merge(globalData, localData);
271287
allData = _.merge(allData, paramData);
272288

core/lib/pattern_assembler.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ const smh = require('./style_modifier_hunter');
1414
const ph = require('./parameter_hunter');
1515
const ch = require('./changes_hunter');
1616
const jsonCopy = require('./json_copy');
17+
const da = require('./data_loader');
1718
const markdown_parser = new mp();
1819
const changes_hunter = new ch();
20+
const dataLoader = new da();
1921

2022
//this is mocked in unit tests
2123
let fs = require('fs-extra'); //eslint-disable-line prefer-const
@@ -35,7 +37,7 @@ const pattern_assembler = function () {
3537
for (var i = 0; i < patternlab.patterns.length; i++) {
3638
switch (partialName) {
3739
case patternlab.patterns[i].relPath:
38-
case patternlab.patterns[i].subdir + '/' + patternlab.patterns[i].fileName:
40+
case patternlab.patterns[i].verbosePartial:
3941
return patternlab.patterns[i];
4042
}
4143
}
@@ -309,16 +311,13 @@ const pattern_assembler = function () {
309311

310312
//look for a json file for this template
311313
try {
312-
var jsonFilename = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".json");
313-
try {
314-
var jsonFilenameStats = fs.statSync(jsonFilename);
315-
} catch (err) {
316-
//not a file
317-
}
318-
if (jsonFilenameStats && jsonFilenameStats.isFile()) {
319-
currentPattern.jsonFileData = fs.readJSONSync(jsonFilename);
314+
var jsonFilename = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName);
315+
const configData = dataLoader.loadDataFromFile(jsonFilename, fs);
316+
317+
if (configData) {
318+
currentPattern.jsonFileData = configData;
320319
if (patternlab.config.debug) {
321-
console.log('processPatternIterative: found pattern-specific data.json for ' + currentPattern.patternPartial);
320+
console.log('processPatternIterative: found pattern-specific config data for ' + currentPattern.patternPartial);
322321
}
323322
}
324323
}
@@ -329,17 +328,14 @@ const pattern_assembler = function () {
329328

330329
//look for a listitems.json file for this template
331330
try {
332-
var listJsonFileName = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".listitems.json");
333-
try {
334-
var listJsonFileStats = fs.statSync(listJsonFileName);
335-
} catch (err) {
336-
//not a file
337-
}
338-
if (listJsonFileStats && listJsonFileStats.isFile()) {
339-
currentPattern.listitems = fs.readJSONSync(listJsonFileName);
331+
var listJsonFileName = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".listitems");
332+
const listItemsConfig = dataLoader.loadDataFromFile(listJsonFileName, fs);
333+
334+
if (listItemsConfig) {
335+
currentPattern.listitems = listItemsConfig;
340336
buildListItems(currentPattern);
341337
if (patternlab.config.debug) {
342-
console.log('found pattern-specific listitems.json for ' + currentPattern.patternPartial);
338+
console.log('found pattern-specific listitems config for ' + currentPattern.patternPartial);
343339
}
344340
}
345341
}

core/lib/pattern_registry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ PatternRegistry.prototype = {
6262
for (const thisPattern of patterns) {
6363
switch (partialName) {
6464
case thisPattern.relPath:
65-
case thisPattern.subdir + '/' + thisPattern.fileName:
65+
case thisPattern.verbosePartial:
6666
return thisPattern;
6767
}
6868
}

core/lib/patternlab.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* patternlab-node - v2.10.0 - 2017
2+
* patternlab-node - v3.0.0-alpha.1 - 2017
33
*
44
* Brian Muenzenmeyer, Geoff Pursell, Raphael Okon, tburny and the web community.
55
* Licensed under the MIT license.
@@ -12,14 +12,14 @@
1212

1313
const diveSync = require('diveSync');
1414
const dive = require('dive');
15-
const glob = require('glob');
1615
const _ = require('lodash');
1716
const path = require('path');
1817
const chalk = require('chalk');
1918
const cleanHtml = require('js-beautify').html;
2019
const inherits = require('util').inherits;
2120
const pm = require('./plugin_manager');
2221
const packageInfo = require('../../package.json');
22+
const dataLoader = require('./data_loader')();
2323
const plutils = require('./utilities');
2424
const jsonCopy = require('./json_copy');
2525
const PatternGraph = require('./pattern_graph').PatternGraph;
@@ -29,6 +29,7 @@ const sm = require('./starterkit_manager');
2929
const pe = require('./pattern_exporter');
3030
const Pattern = require('./object_factory').Pattern;
3131
const CompileState = require('./object_factory').CompileState;
32+
const updateNotifier = require('update-notifier');
3233

3334
//these are mocked in unit tests, so let them be overridden
3435
let fs = require('fs-extra'); // eslint-disable-line
@@ -48,14 +49,20 @@ plutils.log.on('info', msg => console.log(msg));
4849
const patternEngines = require('./pattern_engines');
4950
const EventEmitter = require('events').EventEmitter;
5051

52+
//bootstrap update notifier
53+
updateNotifier({
54+
pkg: packageInfo,
55+
updateCheckInterval: 1000 * 60 * 60 * 24 // notify at most once a day
56+
}).notify();
57+
58+
/**
59+
* Given a path, load info from the folder to compile into a single config object.
60+
* @param dataFilesPath
61+
* @param fsDep
62+
* @returns {{}}
63+
*/
5164
function buildPatternData(dataFilesPath, fsDep) {
52-
const dataFiles = glob.sync(dataFilesPath + '*.json', {"ignore" : [dataFilesPath + 'listitems.json']});
53-
let mergeObject = {};
54-
dataFiles.forEach(function (filePath) {
55-
const jsonData = fsDep.readJSONSync(path.resolve(filePath), 'utf8');
56-
mergeObject = _.merge(mergeObject, jsonData);
57-
});
58-
return mergeObject;
65+
return dataLoader.loadDataFromFolder(dataFilesPath, 'listitems', fsDep);
5966
}
6067

6168
// GTP: these two diveSync pattern processors factored out so they can be reused
@@ -542,9 +549,9 @@ const patternlab_engine = function (config) {
542549
patternlab.data = {};
543550
}
544551
try {
545-
patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json'));
552+
patternlab.listitems = dataLoader.loadDataFromFile(path.resolve(paths.source.data, 'listitems'), fs);
546553
} catch (ex) {
547-
plutils.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems.json file. Pattern Lab may not work without this file.');
554+
plutils.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems file. Pattern Lab may not work without this file.');
548555
patternlab.listitems = {};
549556
}
550557
try {

core/lib/ui_builder.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@ const ui_builder = function () {
595595
//plugins
596596
output += 'var plugins = ' + JSON.stringify(patternlab.plugins || []) + ';' + eol;
597597

598+
//theme
599+
output += 'var theme = ' + JSON.stringify(patternlab.config.theme) + ';' + eol;
600+
598601
//smaller config elements
599602
output += 'var defaultShowPatternInfo = ' + (patternlab.config.defaultShowPatternInfo ? patternlab.config.defaultShowPatternInfo : 'false') + ';' + eol;
600603
output += 'var defaultPattern = "' + (patternlab.config.defaultPattern ? patternlab.config.defaultPattern : 'all') + '";' + eol;

0 commit comments

Comments
 (0)