Skip to content

Commit b918c8d

Browse files
Merge pull request #592 from pattern-lab/dev
Pattern Lab Node Core 2.7.1
2 parents ffcec17 + b7a62ec commit b918c8d

11 files changed

+211
-70
lines changed

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test/
2+
.github/
3+
.travis.yml

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[![Build Status](https://travis-ci.org/pattern-lab/patternlab-node.png?branch=master)](https://travis-ci.org/pattern-lab/patternlab-node) ![current release](https://img.shields.io/github/release/pattern-lab/patternlab-node.svg) ![license](https://img.shields.io/github/license/pattern-lab/patternlab-node.svg) [![Join the chat at Gitter](https://badges.gitter.im/pattern-lab/node.svg)](https://gitter.im/pattern-lab/node)
1+
[![Build Status](https://travis-ci.org/pattern-lab/patternlab-node.svg?branch=master)](https://travis-ci.org/pattern-lab/patternlab-node) ![current release](https://img.shields.io/github/release/pattern-lab/patternlab-node.svg) ![license](https://img.shields.io/github/license/pattern-lab/patternlab-node.svg) [![Join the chat at Gitter](https://badges.gitter.im/pattern-lab/node.svg)](https://gitter.im/pattern-lab/node)
22

33
# Pattern Lab Node Core
44

@@ -12,14 +12,17 @@ If this looks **REALLY DIFFERENT** from what you expected, check out the [Change
1212

1313
* [@bmuenzenmeyer](https://github.com/bmuenzenmeyer) - Lead Maintainer
1414
* [@geoffp](https://github.com/geoffp) - Core Contributor
15+
* [@raphaelokon](https://github.com/raphaelokon) - CLI Contributor
16+
* [@tburny](https://github.com/tburny) - Core Contributor
1517

1618
## Upgrading
1719

1820
If you find yourself here and are looking to upgrade, check out how to upgrade from version to version of Pattern Lab Node here: [https://github.com/pattern-lab/patternlab-node/wiki/Upgrading](https://github.com/pattern-lab/patternlab-node/wiki/Upgrading)
1921

2022
## Command Line Interface
2123

22-
The [command line interface](https://github.com/pattern-lab/patternlab-node/wiki/Command-Line-Interface) is documented in the wiki, and already implemented for you within [Node Editions](https://github.com/pattern-lab?utf8=%E2%9C%93&query=edition-node).
24+
The rudimentary [command line interface](https://github.com/pattern-lab/patternlab-node/wiki/Command-Line-Interface) is documented in the wiki, and already implemented for you within [Node Editions](https://github.com/pattern-lab?utf8=%E2%9C%93&query=edition-node).
25+
A [full-featured command line interface](https://github.com/pattern-lab/patternlab-node-cli) is in the works, courtesy of [@raphaelokon](https://github.com/raphaelokon).
2326

2427
## Contributing
2528

core/lib/changes_hunter.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,32 @@ ChangesHunter.prototype = {
2727
let renderedTemplatePath =
2828
patternlab.config.paths.public.patterns + pattern.getPatternLink(patternlab, 'rendered');
2929

30+
//write the compiled template to the public patterns directory
31+
let markupOnlyPath =
32+
patternlab.config.paths.public.patterns + pattern.getPatternLink(patternlab, 'markupOnly');
33+
3034
if (!pattern.compileState) {
3135
pattern.compileState = CompileState.NEEDS_REBUILD;
3236
}
3337

3438
try {
35-
// Prevent error message if file does not exist
36-
fs.accessSync(renderedTemplatePath, fs.F_OK);
39+
40+
// renderedTemplatePath required to display a single element
41+
// Markup only is required for "View All" pages. It will get loaded later on.
42+
// If any of these is missing, mark pattern for recompile
43+
[renderedTemplatePath, markupOnlyPath].forEach(renderedFile =>
44+
45+
// Prevent error message if file does not exist
46+
fs.accessSync(renderedFile, fs.F_OK)
47+
);
3748
let outputLastModified = fs.statSync(renderedTemplatePath).mtime.getTime();
3849

3950
if (pattern.lastModified && outputLastModified > pattern.lastModified) {
4051
pattern.compileState = CompileState.CLEAN;
4152
}
4253
} catch (e) {
43-
// Output does not exist yet, needs recompile
54+
// Output does not exist yet, force recompile
55+
pattern.compileState = CompileState.NEEDS_REBUILD;
4456
}
4557

4658
let node = patternlab.graph.node(pattern);
@@ -75,7 +87,14 @@ ChangesHunter.prototype = {
7587
// Ignore, not a regular file
7688
}
7789
}
90+
},
91+
92+
needsRebuild: function (lastModified, p) {
93+
if (p.compileState !== CompileState.CLEAN || ! p.lastModified) {
94+
return true;
95+
}
96+
return p.lastModified >= lastModified;
7897
}
7998
};
8099

81-
module.exports = ChangesHunter;
100+
module.exports = ChangesHunter;

core/lib/pattern_assembler.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use strict";
22

33
var path = require('path'),
4+
_ = require('lodash'),
45
fs = require('fs-extra'),
56
Pattern = require('./object_factory').Pattern,
67
CompileState = require('./object_factory').CompileState,
@@ -15,8 +16,8 @@ var path = require('path'),
1516
ch = require('./changes_hunter'),
1617
JSON5 = require('json5');
1718

18-
var markdown_parser = new mp();
19-
var changes_hunter = new ch();
19+
const markdown_parser = new mp();
20+
const changes_hunter = new ch();
2021

2122
var pattern_assembler = function () {
2223
// HELPER FUNCTIONS
@@ -155,6 +156,8 @@ var pattern_assembler = function () {
155156

156157
try {
157158
var markdownFileName = path.resolve(patternlab.config.paths.source.patterns, currentPattern.subdir, currentPattern.fileName + ".md");
159+
changes_hunter.checkLastModified(currentPattern, markdownFileName);
160+
158161
var markdownFileContents = fs.readFileSync(markdownFileName, 'utf8');
159162

160163
var markdownObject = markdown_parser.parse(markdownFileContents);
@@ -404,13 +407,40 @@ var pattern_assembler = function () {
404407
decomposePattern(currentPattern, patternlab);
405408
}
406409

407-
function findModifiedPatterns(lastModified, patternlab) {
408-
return patternlab.patterns.filter(p => {
409-
if (p.compileState !== CompileState.CLEAN || ! p.lastModified) {
410-
return true;
410+
411+
/**
412+
* Finds patterns that were modified and need to be rebuilt. For clean patterns load the already
413+
* rendered markup.
414+
*
415+
* @param lastModified
416+
* @param patternlab
417+
*/
418+
function markModifiedPatterns(lastModified, patternlab) {
419+
/**
420+
* If the given array exists, apply a function to each of its elements
421+
* @param {Array} array
422+
* @param {Function} func
423+
*/
424+
const forEachExisting = (array, func) => {
425+
if (array) {
426+
array.forEach(func);
411427
}
412-
return p.lastModified >= lastModified;
428+
};
429+
const modifiedOrNot = _.groupBy(
430+
patternlab.patterns,
431+
p => changes_hunter.needsRebuild(lastModified, p) ? 'modified' : 'notModified');
432+
433+
// For all unmodified patterns load their rendered template output
434+
forEachExisting(modifiedOrNot.notModified, cleanPattern => {
435+
const xp = path.join(patternlab.config.paths.public.patterns, cleanPattern.getPatternLink(patternlab, 'markupOnly'));
436+
437+
// Pattern with non-existing markupOnly files were already marked for rebuild and thus are not "CLEAN"
438+
cleanPattern.patternPartialCode = fs.readFileSync(xp, 'utf8');
413439
});
440+
441+
// For all patterns that were modified, schedule them for rebuild
442+
forEachExisting(modifiedOrNot.modified, p => p.compileState = CompileState.NEEDS_REBUILD);
443+
return modifiedOrNot;
414444
}
415445

416446
function expandPartials(foundPatternPartials, list_item_hunter, patternlab, currentPattern) {
@@ -526,8 +556,8 @@ var pattern_assembler = function () {
526556
}
527557

528558
return {
529-
find_modified_patterns: function (lastModified, patternlab) {
530-
return findModifiedPatterns(lastModified, patternlab);
559+
mark_modified_patterns: function (lastModified, patternlab) {
560+
return markModifiedPatterns(lastModified, patternlab);
531561
},
532562
find_pattern_partials: function (pattern) {
533563
return pattern.findPartials();

core/lib/pattern_graph.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ var nodeName =
5555

5656
PatternGraph.prototype = {
5757

58+
/**
59+
* Synchronizes the graph nodes with the set of all known patterns.
60+
* For instance when a pattern is deleted or moved, it might still have a node from the serialized
61+
* JSON, but there is no source pattern.
62+
*
63+
* @see {@link https://github.com/pattern-lab/patternlab-node/issues/580|Issue #580}
64+
*/
65+
sync: function () {
66+
// Remove any patterns that are in the graph data, but that haven't been discovered when
67+
// walking all patterns iteratively
68+
const nodesToRemove = this.nodes().filter(n => !this.patterns.has(n));
69+
nodesToRemove.forEach(n => this.remove(n));
70+
return nodesToRemove;
71+
},
72+
5873
/**
5974
* Creates an independent copy of the graph where nodes and edges can be modified without
6075
* affecting the source.
@@ -362,7 +377,7 @@ PatternGraph.resolveJsonGraphFile = function (patternlab, file) {
362377
PatternGraph.loadFromFile = function (patternlab, file) {
363378
const jsonGraphFile = this.resolveJsonGraphFile(patternlab, file);
364379

365-
// File is fresh, so simply constuct an empty graph in memory
380+
// File is fresh, so simply construct an empty graph in memory
366381
if (!fs.existsSync(jsonGraphFile)) {
367382
return PatternGraph.empty();
368383
}

core/lib/patternlab.js

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
2-
* patternlab-node - v2.7.1-alpha - 2016
2+
* patternlab-node - v2.7.1 - 2017
33
*
4-
* Brian Muenzenmeyer, Geoff Pursell, and the web community.
4+
* Brian Muenzenmeyer, Geoff Pursell, Raphael Okon, tburny and the web community.
55
* Licensed under the MIT license.
66
*
77
* Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
@@ -438,10 +438,50 @@ var patternlab_engine = function (config) {
438438
return true;
439439
}
440440

441+
/**
442+
* If a graph was serialized and then {@code deletePatternDir == true}, there is a mismatch in the
443+
* pattern metadata and not all patterns might be recompiled.
444+
* For that reason an empty graph is returned in this case, so every pattern will be flagged as
445+
* "needs recompile". Otherwise the pattern graph is loaded from the meta data.
446+
*
447+
* @param patternlab
448+
* @param {boolean} deletePatternDir When {@code true}, an empty graph is returned
449+
* @return {PatternGraph}
450+
*/
451+
function loadPatternGraph(deletePatternDir) {
452+
// Sanity check to prevent problems when code is refactored
453+
if (deletePatternDir) {
454+
return PatternGraph.empty();
455+
}
456+
return PatternGraph.loadFromFile(patternlab);
457+
}
458+
441459
function buildPatterns(deletePatternDir) {
442460

443461
patternlab.events.emit('patternlab-build-pattern-start', patternlab);
444-
patternlab.graph = PatternGraph.loadFromFile(patternlab);
462+
463+
let graph = patternlab.graph = loadPatternGraph(deletePatternDir);
464+
465+
let graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
466+
467+
if (graphNeedsUpgrade) {
468+
plutils.log.info("Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. " +
469+
"Incremental build is available again on the next successful run.");
470+
471+
// Ensure that the freshly built graph has the latest version again.
472+
patternlab.graph.upgradeVersion();
473+
}
474+
475+
// Flags
476+
let incrementalBuildsEnabled = !(deletePatternDir || graphNeedsUpgrade);
477+
478+
if (incrementalBuildsEnabled) {
479+
plutils.log.info("Incremental builds enabled.");
480+
} else {
481+
// needs to be done BEFORE processing patterns
482+
fs.removeSync(paths.public.patterns);
483+
fs.emptyDirSync(paths.public.patterns);
484+
}
445485

446486
try {
447487
patternlab.data = buildPatternData(paths.source.data, fs);
@@ -511,34 +551,27 @@ var patternlab_engine = function (config) {
511551
cacheBuster: patternlab.cacheBuster
512552
});
513553

514-
let patternsToBuild = patternlab.patterns;
515-
516-
let graphNeedsUpgrade = !PatternGraph.checkVersion(patternlab.graph);
554+
// If deletePatternDir == true or graph needs to be updated
555+
// rebuild all patterns
556+
let patternsToBuild = null;
517557

518-
// Incremental builds are enabled, but we cannot use them
519-
if (!deletePatternDir && graphNeedsUpgrade) {
520-
plutils.log.info("Due to an upgrade, a complete rebuild is required. " +
521-
"Incremental build is available again on the next run.");
522-
523-
// Ensure that the freshly built graph has the latest version again.
524-
patternlab.graph.upgradeVersion();
525-
}
558+
if (incrementalBuildsEnabled) {
559+
// When the graph was loaded from file, some patterns might have been moved/deleted between runs
560+
// so the graph data become out of sync
561+
patternlab.graph.sync().forEach(n => {
562+
plutils.log.info("[Deleted/Moved] " + n);
563+
});
526564

527-
//delete the contents of config.patterns.public before writing
528-
//Also if the serialized graph must be updated
529-
if (deletePatternDir || graphNeedsUpgrade) {
530-
fs.removeSync(paths.public.patterns);
531-
fs.emptyDirSync(paths.public.patterns);
532-
} else {
533565
// TODO Find created or deleted files
534566
let now = new Date().getTime();
535-
var modified = pattern_assembler.find_modified_patterns(now, patternlab);
536-
537-
// First mark all modified files
538-
for (let p of modified) {
567+
pattern_assembler.mark_modified_patterns(now, patternlab);
568+
patternsToBuild = patternlab.graph.compileOrder();
569+
} else {
570+
// build all patterns, mark all to be rebuilt
571+
patternsToBuild = patternlab.patterns;
572+
for (let p of patternsToBuild) {
539573
p.compileState = CompileState.NEEDS_REBUILD;
540574
}
541-
patternsToBuild = patternlab.graph.compileOrder();
542575
}
543576

544577

core/lib/ui_builder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ var ui_builder = function () {
568568
output += 'var ishControls = {"ishControlsHide":' + JSON.stringify(patternlab.config.ishControlsHide) + '};' + eol;
569569

570570
//navItems
571-
output += 'var navItems = {"patternTypes": ' + JSON.stringify(patternlab.patternTypes) + '};' + eol;
571+
output += 'var navItems = {"patternTypes": ' + JSON.stringify(patternlab.patternTypes) + ', "ishControlsHide": ' + JSON.stringify(patternlab.config.ishControlsHide) + '};' + eol;
572572

573573
//patternPaths
574574
output += 'var patternPaths = ' + JSON.stringify(patternlab.patternPaths) + ';' + eol;

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "patternlab-node",
33
"description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).",
4-
"version": "2.7.1-alpha",
4+
"version": "2.7.1",
55
"main": "./core/lib/patternlab.js",
66
"dependencies": {
77
"diveSync": "^0.3.0",
@@ -41,6 +41,12 @@
4141
"contributors": [
4242
{
4343
"name": "Geoff Pursell"
44+
},
45+
{
46+
"name": "Raphael Okon"
47+
},
48+
{
49+
"name": "tburny"
4450
}
4551
],
4652
"license": "MIT",

0 commit comments

Comments
 (0)