diff --git a/README.md b/README.md index a8160bcd6..e4df10ca5 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ patternlab.serve({ ``` -* Read more about [configuration](https://github.com/pattern-lab/patternlab-node/wiki/Configuration) via `patternlab-config.json`. +* Read more about [configuration](http://patternlab.io/docs/advanced-config-options.html#node) via `patternlab-config.json`. * Read more about the rest of [Public API](https://github.com/pattern-lab/patternlab-node/wiki/Public-API), and already implemented for you within [Editions](#editions). diff --git a/core/lib/annotation_exporter.js b/core/lib/annotation_exporter.js index 4f4cb426a..ca1f99969 100644 --- a/core/lib/annotation_exporter.js +++ b/core/lib/annotation_exporter.js @@ -4,23 +4,23 @@ const glob = require('glob'); const fs = require('fs-extra'); const _ = require('lodash'); const mp = require('./markdown_parser'); +const logger = require('./log'); const annotations_exporter = function (pl) { const paths = pl.config.paths; let oldAnnotations; - /* - Returns the array of comments that used to be wrapped in raw JS. + /** + * Parses JS annotations. + * @returns array of comments that used to be wrapped in raw JS */ function parseAnnotationsJS() { //attempt to read the file try { oldAnnotations = fs.readFileSync(path.resolve(paths.source.annotations, 'annotations.js'), 'utf8'); } catch (ex) { - if (pl.config.debug) { - console.log('annotations.js file missing from ' + paths.source.annotations + '. This may be expected.'); - } + logger.debug(`annotations.js file missing from ${paths.source.annotations}. This may be expected if you do not use annotations or are using markdown.`); return []; } @@ -31,13 +31,18 @@ const annotations_exporter = function (pl) { try { var oldAnnotationsJSON = JSON.parse(oldAnnotations); } catch (ex) { - console.log('There was an error parsing JSON for ' + paths.source.annotations + 'annotations.js'); - console.log(ex); + logger.error(`There was an error parsing JSON for ${paths.source.annotations}annotations.js`); return []; } return oldAnnotationsJSON.comments; } + /** + * Build the annotation markdown. + * @param annotationsYAML + * @param markdown_parser + * @returns annotation + */ function buildAnnotationMD(annotationsYAML, markdown_parser) { const annotation = {}; const markdownObj = markdown_parser.parse(annotationsYAML); @@ -48,6 +53,11 @@ const annotations_exporter = function (pl) { return annotation; } + /** + * Parse markdown file annotations. + * @param annotations + * @param parser + */ function parseMDFile(annotations, parser) { //let annotations = annotations; const markdown_parser = parser; @@ -65,8 +75,10 @@ const annotations_exporter = function (pl) { }; } - /* - Converts the *.md file yaml list into an array of annotations + /** + * Converts the *.md file yaml list into an array of annotations + * + * @returns annotations */ function parseAnnotationsMD() { const markdown_parser = new mp(); @@ -77,6 +89,11 @@ const annotations_exporter = function (pl) { return annotations; } + /** + * Gathers JS & MD annotations. + * + * @returns array of annotations + */ function gatherAnnotations() { const annotationsJS = parseAnnotationsJS(); const annotationsMD = parseAnnotationsMD(); diff --git a/core/lib/asset_copy.js b/core/lib/asset_copy.js index 9ac0d7a3c..1e512a96a 100644 --- a/core/lib/asset_copy.js +++ b/core/lib/asset_copy.js @@ -2,6 +2,7 @@ const _ = require('lodash'); const path = require('path'); const process = require('process'); +const logger = require('./log'); let copy = require('recursive-copy'); // eslint-disable-line prefer-const let chokidar = require('chokidar'); // eslint-disable-line prefer-const @@ -40,9 +41,7 @@ const asset_copier = () => { dest, options ).on(copy.events.COPY_FILE_COMPLETE, () => { - if (options.debug) { - console.log(`Moved ${p} to ${dest}`); - } + logger.debug(`Moved ${p} to ${dest}`); options.emitter.emit('patternlab-asset-change', { file: p, dest: dest @@ -70,9 +69,7 @@ const asset_copier = () => { //if we want to watch files, do so, otherwise just copy each file if (options.watch) { - if (patternlab.config.debug) { - console.log(`Pattern Lab is watching ${path.resolve(basePath, dir.source)} for changes`); - } + logger.info(`Pattern Lab is watching ${path.resolve(basePath, dir.source)} for changes`); if (patternlab.watchers[key]) { patternlab.watchers[key].close(); @@ -130,9 +127,7 @@ const asset_copier = () => { _.each(globalPaths, (globalPath) => { - if (patternlab.config.debug) { - console.log(`Pattern Lab is watching ${globalPath} for changes`); - } + logger.info(`Pattern Lab is watching ${globalPath} for changes`); if (patternlab.watchers[globalPath]) { patternlab.watchers[globalPath].close(); @@ -180,9 +175,8 @@ const asset_copier = () => { ) ); _.each(patternWatches, (patternWatchPath) => { - if (patternlab.config.debug) { - console.log(`Pattern Lab is watching ${patternWatchPath} for changes`); - } + + logger.info(`Pattern Lab is watching ${patternWatchPath} for changes`); const patternWatcher = chokidar.watch( path.resolve(patternWatchPath), diff --git a/core/lib/json_copy.js b/core/lib/json_copy.js index 84c9e249d..17bbd9af9 100644 --- a/core/lib/json_copy.js +++ b/core/lib/json_copy.js @@ -1,13 +1,13 @@ "use strict"; -const plutils = require('./utilities'); +const logger = require('./log'); const json_copy = (data, callee) => { try { return JSON.parse(JSON.stringify(data)); } catch (e) { //this is unlikely to be hit due to the passed in data already being loaded using JSON parsers - plutils.error(`JSON provided by ${callee} is invalid and cannot be copied`); - return {}; + logger.warning(`JSON provided by ${callee} is invalid and cannot be copied`); + throw (e); } }; diff --git a/core/lib/lineage_hunter.js b/core/lib/lineage_hunter.js index 7c61be98d..7bcd4a19f 100644 --- a/core/lib/lineage_hunter.js +++ b/core/lib/lineage_hunter.js @@ -1,5 +1,6 @@ 'use strict'; const extend = require("util")._extend; +const logger = require('./log'); const lineage_hunter = function () { @@ -119,9 +120,8 @@ const lineage_hunter = function () { const patternReverseStateIndex = patternStateCascade.indexOf(lineageRPattern.patternState); if (lineageRPattern.patternState === '' || (patternStateIndex < patternReverseStateIndex)) { - if (patternlab.config.debug) { - console.log('Found a lower common denominator pattern state: ' + pattern.patternState + ' on ' + pattern.patternPartial + '. Setting reverse lineage pattern ' + lineageRPattern.patternPartial + ' from ' + (lineageRPattern.patternState === '' ? '<>' : lineageRPattern.patternState)); - } + const oldState = lineageRPattern.patternState === '' ? '<>' : lineageRPattern.patternState; + logger.info(`Found a lower common denominator pattern state: ${pattern.patternState} on ${pattern.patternPartial}. Setting reverse lineage pattern ${lineageRPattern.patternPartial} from ${oldState}`); lineageRPattern.patternState = pattern.patternState; diff --git a/core/lib/list_item_hunter.js b/core/lib/list_item_hunter.js index 7ffe450de..846ecc7d8 100644 --- a/core/lib/list_item_hunter.js +++ b/core/lib/list_item_hunter.js @@ -7,6 +7,7 @@ const list_item_hunter = function () { const smh = require('./style_modifier_hunter'); const jsonCopy = require('./json_copy'); const Pattern = require('./object_factory').Pattern; + const logger = require('./log'); const pattern_assembler = new pa(); const style_modifier_hunter = new smh(); @@ -19,9 +20,7 @@ const list_item_hunter = function () { if (matches !== null) { matches.forEach(function (liMatch) { - if (patternlab.config.debug) { - console.log('found listItem of size ' + liMatch + ' inside ' + pattern.patternPartial); - } + logger.debug(`found listItem of size ${liMatch} inside ${pattern.patternPartial}`); //find the boundaries of the block const loopNumberString = liMatch.split('.')[1].split('}')[0].trim(); @@ -32,9 +31,8 @@ const list_item_hunter = function () { const repeatedBlockTemplate = []; let repeatedBlockHtml = ''; for (let i = 0; i < items.indexOf(loopNumberString); i++) { - if (patternlab.config.debug) { - console.log('list item(s) in pattern', pattern.patternPartial, 'adding', patternBlock, 'to repeatedBlockTemplate'); - } + + logger.debug(`list item(s) in pattern ${pattern.patternPartial}, adding ${patternBlock} to repeatedBlockTemplate`); repeatedBlockTemplate.push(patternBlock); } @@ -43,8 +41,8 @@ const list_item_hunter = function () { try { listData = jsonCopy(patternlab.listitems, 'config.paths.source.data listitems'); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.warning(`There was an error parsing JSON for ${pattern.relPath}`); + logger.warning(err); } listData = _.merge(listData, pattern.listitems); @@ -64,8 +62,8 @@ const list_item_hunter = function () { globalData = jsonCopy(patternlab.data, 'config.paths.source.data global data'); localData = jsonCopy(pattern.jsonFileData, `${pattern.patternPartial} data`); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.warning(`There was an error parsing JSON for ${pattern.relPath}`); + logger.warning(err); } let allData = _.merge(globalData, localData); @@ -89,8 +87,8 @@ const list_item_hunter = function () { cleanPartialPattern = JSON.parse(JSON.stringify(partialPattern)); cleanPartialPattern = jsonCopy(partialPattern, `partial pattern ${partialName}`); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.warning(`There was an error parsing JSON for ${pattern.relPath}`); + logger.warning(err); } //if we retrieved a pattern we should make sure that its extendedTemplate is reset. looks to fix #356 diff --git a/core/lib/utilities.js b/core/lib/log.js similarity index 86% rename from core/lib/utilities.js rename to core/lib/log.js index 6c88dac90..661cf6a05 100644 --- a/core/lib/utilities.js +++ b/core/lib/log.js @@ -31,9 +31,17 @@ const log = Object.assign({ */ const debug = log.debug.bind(log); +/** + * @func info + * @desc Coloured info log + * @param {*} msg - The variadic messages to log out. + * @return {void} + */ +const info = log.info.bind(log); + /** * @func warning - * @desc Coloured error log + * @desc Coloured warning log * @param {*} e - The variadic messages to log out. * @return {void} */ @@ -62,6 +70,7 @@ const reportError = function (message) { module.exports = { debug, + info, warning, error, log, diff --git a/core/lib/markdown_parser.js b/core/lib/markdown_parser.js index 68fcfa68d..68ab4c42d 100644 --- a/core/lib/markdown_parser.js +++ b/core/lib/markdown_parser.js @@ -1,6 +1,7 @@ 'use strict'; const md = require('markdown-it')(); const yaml = require('js-yaml'); +const logger = require('./log'); const markdown_parser = function () { @@ -36,8 +37,8 @@ const markdown_parser = function () { returnObject.markdown = md.render(block); } } catch (ex) { - console.log(ex); - console.log('error parsing markdown block', block); + logger.warning(ex); + logger.warning(`error parsing markdown block ${block}`); return undefined; } diff --git a/core/lib/parameter_hunter.js b/core/lib/parameter_hunter.js index f236f5e31..f6e59e405 100644 --- a/core/lib/parameter_hunter.js +++ b/core/lib/parameter_hunter.js @@ -8,6 +8,7 @@ const parameter_hunter = function () { const smh = require('./style_modifier_hunter'); const style_modifier_hunter = new smh(); const pattern_assembler = new pa(); + const logger = require('./log'); /** * This function is really to accommodate the lax JSON-like syntax allowed by @@ -49,10 +50,9 @@ const parameter_hunter = function () { * * Return paramStringWellFormed. * * @param {string} pString - * @param {object} patternlab * @returns {string} paramStringWellFormed */ - function paramToJson(pString, patternlab) { + function paramToJson(pString) { let colonPos = -1; const keys = []; let paramString = pString; // to not reassign param @@ -67,10 +67,7 @@ const parameter_hunter = function () { paramStringWellFormed = JSON.stringify(JSON.parse(pString)); return paramStringWellFormed; } catch (err) { - //todo this might be a good candidate for a different log level, should we implement that someday - if (patternlab.config.debug) { - console.log(`Not valid JSON found for passed pattern parameter ${pString} will attempt to parse manually...`); - } + logger.debug(`Not valid JSON found for passed pattern parameter ${pString} will attempt to parse manually...`); } //replace all escaped double-quotes with escaped unicode @@ -256,15 +253,13 @@ const parameter_hunter = function () { //if we retrieved a pattern we should make sure that its extendedTemplate is reset. looks to fix #190 partialPattern.extendedTemplate = partialPattern.template; - if (patternlab.config.debug) { - console.log('found patternParameters for ' + partialName); - } + logger.debug(`found patternParameters for ${partialName}`); //strip out the additional data, convert string to JSON. const leftParen = pMatch.indexOf('('); const rightParen = pMatch.lastIndexOf(')'); const paramString = '{' + pMatch.substring(leftParen + 1, rightParen) + '}'; - const paramStringWellFormed = paramToJson(paramString, patternlab); + const paramStringWellFormed = paramToJson(paramString); let paramData = {}; let globalData = {}; @@ -275,8 +270,8 @@ const parameter_hunter = function () { globalData = jsonCopy(patternlab.data, 'config.paths.source.data global data'); localData = jsonCopy(pattern.jsonFileData || {}, `pattern ${pattern.patternPartial} data`); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.warning(`There was an error parsing JSON for ${pattern.relPath}`); + logger.warning(err); } // resolve any pattern links that might be present diff --git a/core/lib/pattern_assembler.js b/core/lib/pattern_assembler.js index 701ef908d..ff9f36295 100644 --- a/core/lib/pattern_assembler.js +++ b/core/lib/pattern_assembler.js @@ -6,7 +6,7 @@ const Pattern = require('./object_factory').Pattern; const CompileState = require('./object_factory').CompileState; const pph = require('./pseudopattern_hunter'); const mp = require('./markdown_parser'); -const plutils = require('./utilities'); +const logger = require('./log'); const patternEngines = require('./pattern_engines'); const lh = require('./lineage_hunter'); const lih = require('./list_item_hunter'); @@ -52,7 +52,7 @@ const pattern_assembler = function () { return patternlab.patterns[i]; } } - plutils.warning('Could not find pattern referenced with partial syntax ' + partialName + '. This can occur when a pattern was renamed, moved, or no longer exists but it still called within a different template somewhere.'); + logger.warning('Could not find pattern referenced with partial syntax ' + partialName + '. This can occur when a pattern was renamed, moved, or no longer exists but it still called within a different template somewhere.'); return undefined; } @@ -103,9 +103,7 @@ const pattern_assembler = function () { // if the pattern is new, we must register it with various data structures! if (isNew) { - if (patternlab.config.debug) { - console.log('found new pattern ' + pattern.patternPartial); - } + logger.debug(`found new pattern ${pattern.patternPartial}`); // do global registration if (pattern.isPattern) { @@ -182,20 +180,15 @@ const pattern_assembler = function () { currentPattern.links = markdownObject.links; } } else { - if (patternlab.config.debug) { - console.log('error processing markdown for ' + currentPattern.patternPartial); - } - } - - if (patternlab.config.debug) { - console.log('found pattern-specific markdown for ' + currentPattern.patternPartial); + logger.warning(`error processing markdown for ${currentPattern.patternPartial}`); } + logger.debug(`found pattern-specific markdown for ${currentPattern.patternPartial}`); } catch (err) { // do nothing when file not found if (err.code !== 'ENOENT') { - console.log('there was an error setting pattern keys after markdown parsing of the companion file for pattern ' + currentPattern.patternPartial); - console.log(err); + logger.warning(`'there was an error setting pattern keys after markdown parsing of the companion file for pattern ${currentPattern.patternPartial}`); + logger.warning(err); } } } @@ -248,15 +241,15 @@ const pattern_assembler = function () { var relativeDepth = (relPath.match(/\w(?=\\)|\w(?=\/)/g) || []).length; if (relativeDepth > 2) { - console.log(''); - plutils.warning('Warning:'); - plutils.warning('A pattern file: ' + relPath + ' was found greater than 2 levels deep from ' + patternlab.config.paths.source.patterns + '.'); - plutils.warning('It\'s strongly suggested to not deviate from the following structure under _patterns/'); - plutils.warning('[patternType]/[patternSubtype]/[patternName].[patternExtension]'); - console.log(''); - plutils.warning('While Pattern Lab may still function, assets may 404 and frontend links may break. Consider yourself warned. '); - plutils.warning('Read More: http://patternlab.io/docs/pattern-organization.html'); - console.log(''); + logger.warning(''); + logger.warning('Warning:'); + logger.warning('A pattern file: ' + relPath + ' was found greater than 2 levels deep from ' + patternlab.config.paths.source.patterns + '.'); + logger.warning('It\'s strongly suggested to not deviate from the following structure under _patterns/'); + logger.warning('[patternType]/[patternSubtype]/[patternName].[patternExtension]'); + logger.warning(''); + logger.warning('While Pattern Lab may still function, assets may 404 and frontend links may break. Consider yourself warned. '); + logger.warning('Read More: http://patternlab.io/docs/pattern-organization.html'); + logger.warning(''); } //check if the found file is a top-level markdown file @@ -282,7 +275,7 @@ const pattern_assembler = function () { } catch (err) { // no file exists, meaning it's a pattern markdown file if (err.code !== 'ENOENT') { - console.log(err); + logger.warning(err); } } } @@ -312,36 +305,32 @@ const pattern_assembler = function () { //look for a json file for this template try { var jsonFilename = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName); - const configData = dataLoader.loadDataFromFile(jsonFilename, fs); + const patternData = dataLoader.loadDataFromFile(jsonFilename, fs); - if (configData) { - currentPattern.jsonFileData = configData; - if (patternlab.config.debug) { - console.log('processPatternIterative: found pattern-specific config data for ' + currentPattern.patternPartial); - } + if (patternData) { + currentPattern.jsonFileData = patternData; + logger.debug(`found pattern-specific data for ${currentPattern.patternPartial}`); } } catch (err) { - console.log('There was an error parsing sibling JSON for ' + currentPattern.relPath); - console.log(err); + logger.warning(`There was an error parsing sibling JSON for ${currentPattern.relPath}`); + logger.warning(err); } //look for a listitems.json file for this template try { var listJsonFileName = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".listitems"); - const listItemsConfig = dataLoader.loadDataFromFile(listJsonFileName, fs); + const listItemsData = dataLoader.loadDataFromFile(listJsonFileName, fs); - if (listItemsConfig) { - currentPattern.listitems = listItemsConfig; + if (listItemsData) { + logger.debug(`found pattern-specific listitems data for ${currentPattern.patternPartial}`); + currentPattern.listitems = listItemsData; buildListItems(currentPattern); - if (patternlab.config.debug) { - console.log('found pattern-specific listitems config for ' + currentPattern.patternPartial); - } } } catch (err) { - console.log('There was an error parsing sibling listitem JSON for ' + currentPattern.relPath); - console.log(err); + logger.warning(`There was an error parsing sibling listitem JSON for ${currentPattern.relPath}`); + logger.warning(err); } //look for a markdown file for this template @@ -382,7 +371,7 @@ const pattern_assembler = function () { //find any pattern parameters that may be in the current pattern pattern.parameteredPartials = pattern.findPartialsWithPatternParameters(); return pattern; - }).catch(plutils.reportError('There was an error in processPatternIterative():')); + }).catch(logger.reportError('There was an error in processPatternIterative():')); } function processPatternRecursive(file, patternlab) { @@ -447,9 +436,7 @@ const pattern_assembler = function () { var style_modifier_hunter = new smh(), parameter_hunter = new ph(); - if (patternlab.config.debug) { - console.log('found partials for ' + currentPattern.patternPartial); - } + logger.debug(`found partials for ${currentPattern.patternPartial}`); // determine if the template contains any pattern parameters. if so they // must be immediately consumed @@ -513,18 +500,15 @@ const pattern_assembler = function () { var fullLink = patternlab.data.link[linkPatternPartial]; if (fullLink) { fullLink = path.normalize(fullLink).replace(/\\/g, '/'); - if (patternlab.config.debug) { - console.log('expanded data link from ' + dataLink + ' to ' + fullLink + ' inside ' + key); - } + + logger.debug(`expanded data link from ${dataLink} to ${fullLink} inside ${key}`); //also make sure our global replace didn't mess up a protocol fullLink = fullLink.replace(/:\//g, '://'); dataObjAsString = dataObjAsString.replace('link.' + linkPatternPartial, fullLink); } } else { - if (patternlab.config.debug) { - console.log('pattern not found for', dataLink, 'inside', key); - } + logger.warning(`pattern not found for ${dataLink} inside ${key}`); } } } @@ -534,8 +518,8 @@ const pattern_assembler = function () { try { dataObj = JSON.parse(dataObjAsString); } catch (err) { - console.log('There was an error parsing JSON for ' + key); - console.log(err); + logger.warning(`There was an error parsing JSON for ${key}`); + logger.warning(err); } return dataObj; diff --git a/core/lib/pattern_engines.js b/core/lib/pattern_engines.js index 8b825ed29..cd681dce7 100644 --- a/core/lib/pattern_engines.js +++ b/core/lib/pattern_engines.js @@ -2,10 +2,10 @@ 'use strict'; const {existsSync, lstatSync, readdirSync} = require('fs'); const path = require('path'); -const chalk = require('chalk'); const engineMatcher = /^patternengine-node-(.*)$/; const scopeMatch = /^@(.*)$/; const isDir = fPath => lstatSync(fPath).isDirectory(); +const logger = require('./log'); const enginesDirectories = [{ displayName: 'the core', @@ -15,12 +15,16 @@ const enginesDirectories = [{ path: path.join(process.cwd(), 'node_modules') }]; -// given a path: return the engine name if the path points to a valid engine -// module directory, or false if it doesn't +/** + * Given a path: return the engine name if the path points to a valid engine + * module directory, or false if it doesn't. + * @param filePath + * @returns Engine name if exists or FALSE + */ function isEngineModule(filePath) { const baseName = path.basename(filePath); const engineMatch = baseName.match(engineMatcher); - + if (engineMatch) { return engineMatch[1]; } return false; } @@ -43,12 +47,12 @@ function isScopedPackage(filePath) { * @return {Array} An array of engine objects */ function resolveEngines(dir) { - + // Guard against non-existent directories. if (!existsSync(dir)) { return []; // Silence is golden … } - + /** * @name walk * @desc Traverse the given path and gather possible engines @@ -57,14 +61,14 @@ function resolveEngines(dir) { * @return {Array} - The final array of engines */ const walk = (fPath, engines) => { - + /** * @name dirList * @desc A list of all directories in the given path * @type {Array} */ const dirList = readdirSync(fPath).filter(p => isDir(path.join(fPath, p))); - + /** * @name e * @desc For the current dir get all engines @@ -76,10 +80,10 @@ function resolveEngines(dir) { return { name: isEngineModule(engine), modulePath: path.join(fPath, engine) - } + }; }) ); - + /** * 1. Flatten all engines from inner recursions and current dir * 2. Filter the dirList for scoped packages @@ -92,12 +96,12 @@ function resolveEngines(dir) { .map(scope => walk(path.join(fPath, scope), e)) // 3 ); }; - + return walk(dir, []); } function findEngineModulesInDirectory(dir) { - const foundEngines = resolveEngines(dir) + const foundEngines = resolveEngines(dir); return foundEngines; } @@ -117,27 +121,28 @@ function findEngineModulesInDirectory(dir) { // methods and properites below should therefore be on its prototype. const PatternEngines = Object.create({ - + + /** + * Load all pattern engines. + * @param patternLabConfig + * @memberof PatternEngines + */ loadAllEngines: function (patternLabConfig) { var self = this; - + // Try to load engines! We scan for engines at each path specified above. This // function is kind of a big deal. enginesDirectories.forEach(function (engineDirectory) { const enginesInThisDir = findEngineModulesInDirectory(engineDirectory.path); - if (patternLabConfig.debug) { - console.log(chalk.bold(`Loading engines from ${engineDirectory.displayName}...\n`)); - } - + + logger.debug(`Loading engines from ${engineDirectory.displayName}...`); + // find all engine-named things in this directory and try to load them, // unless it's already been loaded. enginesInThisDir.forEach(function (engineDiscovery) { let errorMessage; const successMessage = "good to go"; - if (patternLabConfig.debug) { - chalk.green(successMessage); - } - + try { // Give it a try! load 'er up. But not if we already have, // of course. Also pass the pattern lab config object into @@ -157,23 +162,24 @@ const PatternEngines = Object.create({ errorMessage = err.message; } finally { // report on the status of the engine, one way or another! - if (patternLabConfig.debug) { - console.log(` ${engineDiscovery.name}:`, errorMessage ? chalk.red(errorMessage) : successMessage); - } + logger.info(`Pattern Engine ${engineDiscovery.name}: ${errorMessage ? errorMessage : successMessage}`); } }); - console.log(''); }); - + // Complain if for some reason we haven't loaded any engines. if (Object.keys(self).length === 0) { - throw new Error('No engines loaded! Something is seriously wrong.'); - } - if (patternLabConfig.debug) { - console.log(chalk.bold('Done loading engines.\n')); + logger.error('No engines loaded! Something is seriously wrong.'); } + logger.debug(`Done loading engines`); }, - + + /** + * Get engine name for pattern. + * @memberof PatternEngines + * @param pattern + * @returns engine name matching pattern + */ getEngineNameForPattern: function (pattern) { // avoid circular dependency by putting this in here. TODO: is this slow? const of = require('./object_factory'); @@ -182,7 +188,7 @@ const PatternEngines = Object.create({ const engineNames = Object.keys(this); for (let i = 0; i < engineNames.length; i++) { const engine = this[engineNames[i]]; - + if (Array.isArray(engine.engineFileExtension)) { if (engine.engineFileExtension.includes(pattern.fileExtension)) { return engine.engineName; @@ -195,12 +201,18 @@ const PatternEngines = Object.create({ } } } - + // otherwise, assume it's a plain mustache template string and act // accordingly return 'mustache'; }, - + + /** + * Get engine for pattern. + * @memberof PatternEngines + * @param pattern + * @returns name of engine for pattern + */ getEngineForPattern: function (pattern) { if (pattern.isPseudoPattern) { return this.getEngineForPattern(pattern.basePattern); @@ -209,8 +221,12 @@ const PatternEngines = Object.create({ return this[engineName]; } }, - - // combine all found engines into a single array of supported extensions + + /** + * Combine all found engines into a single array of supported extensions. + * @memberof PatternEngines + * @returns Array all supported file extensions + */ getSupportedFileExtensions: function () { const engineNames = Object.keys(PatternEngines); const allEnginesExtensions = engineNames.map((engineName) => { @@ -218,23 +234,39 @@ const PatternEngines = Object.create({ }); return [].concat.apply([], allEnginesExtensions); }, - + + /** + * Check if fileExtension is supported. + * @memberof PatternEngines + * @param fileExtension + * @returns Boolean + */ isFileExtensionSupported: function (fileExtension) { const supportedExtensions = PatternEngines.getSupportedFileExtensions(); return (supportedExtensions.lastIndexOf(fileExtension) !== -1); }, - - // given a filename, return a boolean: whether or not the filename indicates - // that the file is pseudopattern JSON + + /** + * Given a filename, return a boolean: whether or not the filename indicates + * that the file is pseudopattern JSON + * @param filename + * @return boolean + */ isPseudoPatternJSON: function (filename) { const extension = path.extname(filename); return (extension === '.json' && filename.indexOf('~') > -1); }, - - // takes a filename string, not a full path; a basename (plus extension) - // ignore _underscored patterns, dotfiles, and anything not recognized by a - // loaded pattern engine. Pseudo-pattern .json files ARE considered to be - // pattern files! + + /** + * Takes a filename string, not a full path; a basename (plus extension) + * ignore _underscored patterns, dotfiles, and anything not recognized by a + * loaded pattern engine. Pseudo-pattern .json files ARE considered to be + * pattern files! + * + * @memberof PatternEngines + * @param filename + * @returns boolean + */ isPatternFile: function (filename) { // skip hidden patterns/files without a second thought const extension = path.extname(filename); @@ -242,7 +274,7 @@ const PatternEngines = Object.create({ (extension === '.json' && !PatternEngines.isPseudoPatternJSON(filename))) { return false; } - + // not a hidden pattern, let's dig deeper const supportedPatternFileExtensions = PatternEngines.getSupportedFileExtensions(); return (supportedPatternFileExtensions.lastIndexOf(extension) !== -1 || diff --git a/core/lib/patternlab.js b/core/lib/patternlab.js index 4143f6dc0..537269404 100644 --- a/core/lib/patternlab.js +++ b/core/lib/patternlab.js @@ -14,13 +14,13 @@ const diveSync = require('diveSync'); const dive = require('dive'); const _ = require('lodash'); const path = require('path'); -const chalk = require('chalk'); const cleanHtml = require('js-beautify').html; const inherits = require('util').inherits; const pm = require('./plugin_manager'); const packageInfo = require('../../package.json'); +const defaultConfig = require('../../patternlab-config.json'); const dataLoader = require('./data_loader')(); -const plutils = require('./utilities'); +const logger = require('./log'); const jsonCopy = require('./json_copy'); const PatternGraph = require('./pattern_graph').PatternGraph; const pa = require('./pattern_assembler'); @@ -41,299 +41,206 @@ let serve = require('./serve'); // eslint-disable-line const pattern_assembler = new pa(); const lineage_hunter = new lh(); -//register our log events -plutils.log.on('error', msg => console.log(msg)); -plutils.log.on('debug', msg => console.log(msg)); -plutils.log.on('warning', msg => console.log(msg)); -plutils.log.on('info', msg => console.log(msg)); - const patternEngines = require('./pattern_engines'); const EventEmitter = require('events').EventEmitter; -//bootstrap update notifier -updateNotifier({ - pkg: packageInfo, - updateCheckInterval: 1000 * 60 * 60 * 24 // notify at most once a day -}).notify(); - -/** - * Given a path, load info from the folder to compile into a single config object. - * @param dataFilesPath - * @param fsDep - * @returns {{}} - */ -function buildPatternData(dataFilesPath, fsDep) { - return dataLoader.loadDataFromFolder(dataFilesPath, 'listitems', fsDep); +function PatternLabEventEmitter() { + EventEmitter.call(this); } +inherits(PatternLabEventEmitter, EventEmitter); -// GTP: these two diveSync pattern processors factored out so they can be reused -// from unit tests to reduce code dupe! -function processAllPatternsIterative(patterns_dir, patternlab) { +class PatternLab { + constructor(config) { + // Either use the config we were passed, or load one up from the config file ourselves + this.config = config || fs.readJSONSync(path.resolve(__dirname, '../../patternlab-config.json')); - const promiseAllPatternFiles = new Promise(function (resolve) { - dive( - patterns_dir, - (err, file) => { - //log any errors - if (err) { - console.log('error in processAllPatternsIterative():', err); - return; - } + //register our log events + this.registerLogger(config.logLevel); - // We now have the loading and process phases spearated; this - // loads all the patterns before beginning any analysis, so we - // can load them asynchronously and be sure we know about all - // of them before we start lineage hunting, for - // example. Incidentally, this should also allow people to do - // horrifying things like include a page in a atom. But - // please, if you're reading this: don't. + logger.info(`Pattern Lab Node v${packageInfo.version}`); - // NOTE: sync for now - pattern_assembler.load_pattern_iterative(path.relative(patterns_dir, file), patternlab); - }, - resolve - ); - }); - return promiseAllPatternFiles.then(() => { - // This is the second phase: once we've loaded all patterns, - // start analysis. - // patternlab.patterns.forEach((pattern) => { - // pattern_assembler.process_pattern_iterative(pattern, patternlab); - // }); - return Promise.all(patternlab.patterns.map((pattern) => { - return pattern_assembler.process_pattern_iterative(pattern, patternlab); - })); - }); -} + // Load up engines please + this.engines = patternEngines; + this.engines.loadAllEngines(config); -function processAllPatternsRecursive(patterns_dir, patternlab) { - diveSync( - patterns_dir, - function (err, file) { - //log any errors - if (err) { - console.log(err); - return; - } - pattern_assembler.process_pattern_recursive(path.relative(patterns_dir, file), patternlab); - } - ); -} + // Cache the package.json in RAM + this.package = fs.readJSONSync(path.resolve(__dirname, '../../package.json')); -function checkConfiguration(patternlab) { - //default the output suffixes if not present - const outputFileSuffixes = { - rendered: '.rendered', - rawTemplate: '', - markupOnly: '.markup-only' - }; + // Make ye olde event emitter + this.events = new PatternLabEventEmitter(); - if (!patternlab.config.outputFileSuffixes) { - plutils.warning('Configuration Object "outputFileSuffixes" not found, and defaulted to the following:'); - console.log(outputFileSuffixes); - plutils.warning('Since Pattern Lab Node Core 2.3.0 this configuration option is required. Suggest you add it to your patternlab-config.json file.'); - console.log(); - } - patternlab.config.outputFileSuffixes = _.extend(outputFileSuffixes, patternlab.config.outputFileSuffixes); + // Make a place for the pattern graph to sit + this.graph = null; - if (typeof patternlab.config.paths.source.patternlabFiles === 'string') { - plutils.warning(`Configuration key [paths.source.patternlabFiles] inside patternlab-config.json was found as the string '${patternlab.config.paths.source.patternlabFiles}'`); - plutils.warning('Since Pattern Lab Node Core 3.0.0 this key is an object. Suggest you update this key following this issue: https://github.com/pattern-lab/patternlab-node/issues/683.'); - } + // Make a place to attach known watchers so we can manage them better during serve and watch + this.watchers = {}; -} - -/** - * Finds and calls the main method of any found plugins. - * @param patternlab - global data store - */ - -//todo, move this to plugin_manager -function initializePlugins(patternlab) { + // Verify correctness of configuration (?) + this.checkConfiguration(this); - if (!patternlab.config.plugins) { return; } - - const plugin_manager = new pm(patternlab.config, path.resolve(__dirname, '../../patternlab-config.json')); - const foundPlugins = plugin_manager.detect_plugins(); + // TODO: determine if this is the best place to wire up plugins + this.initializePlugins(this); + } - if (foundPlugins && foundPlugins.length > 0) { + checkConfiguration(patternlab) { - for (let i = 0; i < foundPlugins.length; i++) { + //default the output suffixes if not present + const outputFileSuffixes = { + rendered: '.rendered', + rawTemplate: '', + markupOnly: '.markup-only' + }; - const pluginKey = foundPlugins[i]; + if (!patternlab.config.outputFileSuffixes) { + logger.warning(''); + logger.warning('Configuration key [outputFileSuffixes] not found, and defaulted to the following:'); + logger.info(outputFileSuffixes); + logger.warning('Since Pattern Lab Node Core 2.3.0 this configuration option is required. Suggest you add it to your patternlab-config.json file.'); + logger.warning(''); + } + patternlab.config.outputFileSuffixes = _.extend(outputFileSuffixes, patternlab.config.outputFileSuffixes); - if (patternlab.config.debug) { - console.log('Found plugin: ', pluginKey); - console.log('Attempting to load and initialize plugin.'); - } + if (typeof patternlab.config.paths.source.patternlabFiles === 'string') { + logger.warning(''); + logger.warning(`Configuration key [paths.source.patternlabFiles] inside patternlab-config.json was found as the string '${patternlab.config.paths.source.patternlabFiles}'`); + logger.warning('Since Pattern Lab Node Core 3.0.0 this key is an object. Suggest you update this key following this issue: https://github.com/pattern-lab/patternlab-node/issues/683.'); + logger.warning(''); + } - const plugin = plugin_manager.load_plugin(pluginKey); - plugin(patternlab); + if (typeof patternlab.config.debug === 'boolean') { + logger.warning(''); + logger.warning(`Configuration key [debug] inside patternlab-config.json was found. As of Pattern Lab Node Core 3.0.0 this key is replaced with a new key, [logLevel]. This is a string with possible values ['debug', 'info', 'warning', 'error', 'quiet'].`); + logger.warning(`Turning on 'info', 'warning', and 'error' levels by default, unless [logLevel] is present. If that is the case, [debug] has no effect.`); + logger.warning(''); } } -} -/** - * Installs a given plugin. Assumes it has already been pulled down via npm - * @param pluginName - the name of the plugin - */ -function installPlugin(pluginName) { - //get the config - const configPath = path.resolve(process.cwd(), 'patternlab-config.json'); - const config = fs.readJSONSync(path.resolve(configPath), 'utf8'); - const plugin_manager = new pm(config, configPath); + /** + * Finds and calls the main method of any found plugins. + * @param patternlab - global data store + */ + //todo, move this to plugin_manager + initializePlugins(patternlab) { - plugin_manager.install_plugin(pluginName); -} + if (!patternlab.config.plugins) { return; } -function PatternLabEventEmitter() { - EventEmitter.call(this); -} -inherits(PatternLabEventEmitter, EventEmitter); + const plugin_manager = new pm(patternlab.config, path.resolve(__dirname, '../../patternlab-config.json')); + const foundPlugins = plugin_manager.detect_plugins(); -const patternlab_engine = function (config) { - const patternlab = {}; + if (foundPlugins && foundPlugins.length > 0) { - patternlab.engines = patternEngines; - patternlab.engines.loadAllEngines(config); + for (let i = 0; i < foundPlugins.length; i++) { - patternlab.package = fs.readJSONSync(path.resolve(__dirname, '../../package.json')); - patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../../patternlab-config.json')); - patternlab.events = new PatternLabEventEmitter(); - patternlab.watchers = {}; + const pluginKey = foundPlugins[i]; - // Initialized when building - patternlab.graph = null; + logger.info(`Found plugin: ${pluginKey}`); + logger.info(`Attempting to load and initialize plugin.`); - checkConfiguration(patternlab); + const plugin = plugin_manager.load_plugin(pluginKey); + plugin(patternlab); + } + } + } - //todo: determine if this is the best place to wire up plugins - initializePlugins(patternlab); + buildGlobalData() { + const paths = this.config.paths; - const paths = patternlab.config.paths; + // + // COLLECT GLOBAL LIBRARY DATA + // - function getVersion() { - return patternlab.package.version; - } + // data.json + try { + this.data = buildPatternData(paths.source.data, fs); // eslint-disable-line no-use-before-define + } catch (ex) { + logger.error('missing or malformed' + paths.source.data + 'data.json Pattern Lab may not work without this file.'); + this.data = {}; + } - function logVersion() { - console.log(patternlab.package.version); - } + // listitems.json + try { + this.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json')); + } catch (ex) { + logger.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems.json file. Pattern Lab may not work without this file.'); + this.listitems = {}; + } - function getSupportedTemplateExtensions() { - return patternlab.engines.getSupportedFileExtensions(); - } + // load up all the necessary files from pattern lab that apply to every template + try { + this.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles['general-header']), 'utf8'); + this.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles['general-footer']), 'utf8'); + this.patternSection = fs.readFileSync(path.resolve(paths.source.patternlabFiles.patternSection), 'utf8'); + this.patternSectionSubType = fs.readFileSync(path.resolve(paths.source.patternlabFiles.patternSectionSubtype), 'utf8'); + this.viewAll = fs.readFileSync(path.resolve(paths.source.patternlabFiles.viewall), 'utf8'); + } catch (ex) { + logger.info(ex); + logger.error('\nERROR: missing an essential file from ' + paths.source.patternlabFiles + '. Pattern Lab won\'t work without this file.\n'); - function help() { + // GTP: it seems increasingly naughty as we refactor to just unilaterally do this here, + // but whatever. For now. + process.exit(1); + } - console.log(''); - - console.log('|=======================================|'); - plutils.debug(' Pattern Lab Node Help v' + patternlab.package.version); - console.log('|=======================================|'); - - console.log(''); - console.log('Command Line Interface - usually consumed by an edition'); - console.log(''); - - plutils.debug(' patternlab:build'); - console.log(' > Compiles the patterns and frontend, outputting to config.paths.public'); - console.log(''); - - plutils.debug(' patternlab:patternsonly'); - console.log(' > Compiles the patterns only, outputting to config.paths.public'); - console.log(''); - - plutils.debug(' patternlab:version'); - console.log(' > Return the version of patternlab-node you have installed'); - console.log(''); - - plutils.debug(' patternlab:help'); - console.log(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.'); - console.log(''); - - plutils.debug(' patternlab:liststarterkits'); - console.log(' > Returns a url with the list of available starterkits hosted on the Pattern Lab organization Github account'); - console.log(''); - - plutils.debug(' patternlab:loadstarterkit'); - console.log(' > Load a starterkit into config.paths.source/*'); - console.log(' > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.'); - console.log(' > NOTE: In most cases, `npm install starterkit-name` will precede this call.'); - console.log(' > arguments:'); - console.log(' -- kit '); - console.log(' > the name of the starter kit to load'); - console.log(' -- clean '); - console.log(' > removes all files from config.paths.source/ prior to load'); - console.log(' > example (gulp):'); - console.log(' `gulp patternlab:loadstarterkit --kit=starterkit-mustache-demo`'); - console.log(''); - - console.log('==============================='); - console.log(''); - console.log('Visit http://patternlab.io/ for more info about Pattern Lab'); - console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.'); - console.log('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.'); - console.log(''); - console.log('==============================='); - } - function printDebug() { - // A replacer function to pass to stringify below; this is here to prevent - // the debug output from blowing up into a massive fireball of circular - // references. This happens specifically with the Handlebars engine. Remove - // if you like 180MB log files. - function propertyStringReplacer(key, value) { - if (key === 'engine' && value && value.engineName) { - return '{' + value.engineName + ' engine object}'; - } - return value; - } + // + // INITIALIZE EMPTY GLOBAL DATA STRUCTURES + // + this.patterns = []; + this.subtypePatterns = {}; + this.partials = {}; + this.data.link = {}; - //debug file can be written by setting flag on patternlab-config.json - if (patternlab.config.debug) { - console.log('writing patternlab debug file to ./patternlab.json'); - fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, propertyStringReplacer, 3)); - } + this.setCacheBust(); + + pattern_assembler.combine_listItems(this); + + this.events.emit('patternlab-build-global-data-end', this); } - function setCacheBust() { - if (patternlab.config.cacheBust) { - if (patternlab.config.debug) { - console.log('setting cacheBuster value for frontend assets.'); - } - patternlab.cacheBuster = new Date().getTime(); + setCacheBust() { + if (this.config.cacheBust) { + logger.debug('setting cacheBuster value for frontend assets.'); + this.cacheBuster = new Date().getTime(); } else { - patternlab.cacheBuster = 0; + this.cacheBuster = 0; } } - function listStarterkits() { - const starterkit_manager = new sm(patternlab.config); + + // Starter Kit loading methods + + listStarterkits() { + const starterkit_manager = new sm(this.config); return starterkit_manager.list_starterkits(); } - function loadStarterKit(starterkitName, clean) { - const starterkit_manager = new sm(patternlab.config); + loadStarterKit(starterkitName, clean) { + const starterkit_manager = new sm(this.config); starterkit_manager.load_starterkit(starterkitName, clean); } + + // Pattern processing methods + /** * Process the user-defined pattern head and prepare it for rendering */ - function processHeadPattern() { + processHeadPattern() { try { - const headPath = path.resolve(paths.source.meta, '_00-head.mustache'); - const headPattern = new Pattern(headPath, null, patternlab); + const headPath = path.resolve(this.config.paths.source.meta, '_00-head.mustache'); + const headPattern = new Pattern(headPath, null, this); headPattern.template = fs.readFileSync(headPath, 'utf8'); headPattern.isPattern = false; headPattern.isMetaPattern = true; - pattern_assembler.decomposePattern(headPattern, patternlab, true); - patternlab.userHead = headPattern.extendedTemplate; + pattern_assembler.decomposePattern(headPattern, this, true); + this.userHead = headPattern.extendedTemplate; } catch (ex) { - plutils.error('\nWARNING: Could not find the user-editable header template, currently configured to be at ' + path.join(config.paths.source.meta, '_00-head.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n'); - if (patternlab.config.debug) { console.log(ex); } + logger.warning(`Could not find the user-editable header template, currently configured to be at ${path.join(this.config.paths.source.meta, '_00-head.ext')}. Your configured path may be incorrect (check this.config.paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.`); + logger.warning(ex); + + // GTP: it seems increasingly naughty as we refactor to just unilaterally do this here, + // but whatever. For now. process.exit(1); } } @@ -341,32 +248,48 @@ const patternlab_engine = function (config) { /** * Process the user-defined pattern footer and prepare it for rendering */ - function processFootPattern() { + processFootPattern() { try { - const footPath = path.resolve(paths.source.meta, '_01-foot.mustache'); - const footPattern = new Pattern(footPath, null, patternlab); + const footPath = path.resolve(this.config.paths.source.meta, '_01-foot.mustache'); + const footPattern = new Pattern(footPath, null, this); footPattern.template = fs.readFileSync(footPath, 'utf8'); footPattern.isPattern = false; footPattern.isMetaPattern = true; - pattern_assembler.decomposePattern(footPattern, patternlab, true); - patternlab.userFoot = footPattern.extendedTemplate; + pattern_assembler.decomposePattern(footPattern, this, true); + this.userFoot = footPattern.extendedTemplate; } catch (ex) { - plutils.error('\nWARNING: Could not find the user-editable footer template, currently configured to be at ' + path.join(config.paths.source.meta, '_01-foot.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n'); - if (patternlab.config.debug) { console.log(ex); } + logger.error(`Could not find the user-editable footer template, currently configured to be at ${path.join(this.config.paths.source.meta, '_01-foot.ext')}. Your configured path may be incorrect (check this.config.paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.`); + logger.warning(ex); + + // GTP: it seems increasingly naughty as we refactor to just unilaterally do this here, + // but whatever. For now. process.exit(1); } } - function writePatternFiles(headHTML, pattern, footerHTML) { + + // info methods + getVersion() { + return this.package.version; + } + logVersion() { + logger.info(this.package.version); + } + getSupportedTemplateExtensions() { + return this.engines.getSupportedFileExtensions(); + } + + + writePatternFiles(headHTML, pattern, footerHTML) { const nullFormatter = str => str; const defaultFormatter = codeString => cleanHtml(codeString, {indent_size: 2}); - const makePath = type => path.join(paths.public.patterns, pattern.getPatternLink(patternlab, type)); + const makePath = type => path.join(this.config.paths.public.patterns, pattern.getPatternLink(this, type)); const patternPage = headHTML + pattern.patternPartialCode + footerHTML; const eng = pattern.engine; //beautify the output if configured to do so - const formatters = config.cleanOutputHtml ? { + const formatters = this.config.cleanOutputHtml ? { rendered: eng.renderedCodeFormatter || defaultFormatter, rawTemplate: eng.rawTemplateCodeFormatter || defaultFormatter, markupOnly: eng.markupOnlyCodeFormatter || defaultFormatter @@ -382,17 +305,194 @@ const patternlab_engine = function (config) { { path: makePath('rawTemplate'), content: formatters.rawTemplate(pattern.template, pattern) }, { path: makePath('markupOnly'), content: formatters.markupOnly(pattern.patternPartialCode, pattern) } ].concat( - eng.addOutputFiles ? eng.addOutputFiles(paths, patternlab) : [] + eng.addOutputFiles ? eng.addOutputFiles(this.config.paths, this) : [] ); //write the compiled template to the public patterns directory outputFiles.forEach(outFile => fs.outputFileSync(outFile.path, outFile.content)); } + /** + * Binds console logging to different levels + * + * @param {string} logLevel + * @memberof PatternLab + */ + registerLogger(logLevel) { + if (logLevel === undefined) { + logger.log.on('info', msg => console.info(msg)); + logger.log.on('warning', msg => console.info(msg)); + logger.log.on('error', msg => console.info(msg)); + } else { + if (logLevel === 'quiet') { return; } + switch (logLevel) { + case 'debug': + logger.log.on('debug', msg => console.info(msg)); + case 'info': + logger.log.on('info', msg => console.info(msg)); + case 'warning': + logger.log.on('warning', msg => console.info(msg)); + case 'error': + logger.log.on('error', msg => console.info(msg)); + } + } + } +} + +//bootstrap update notifier +updateNotifier({ + pkg: packageInfo, + updateCheckInterval: 1000 * 60 * 60 * 24 // notify at most once a day +}).notify(); + +/** + * Given a path, load info from the folder to compile into a single config object. + * @param dataFilesPath + * @param fsDep + * @returns {{}} + */ +function buildPatternData(dataFilesPath, fsDep) { + return dataLoader.loadDataFromFolder(dataFilesPath, 'listitems', fsDep); +} + +// GTP: these two diveSync pattern processors factored out so they can be reused +// from unit tests to reduce code dupe! +function processAllPatternsIterative(patterns_dir, patternlab) { + + const promiseAllPatternFiles = new Promise(function (resolve) { + dive( + patterns_dir, + (err, file) => { + //log any errors + if (err) { + logger.info('error in processAllPatternsIterative():', err); + return; + } + + // We now have the loading and process phases spearated; this + // loads all the patterns before beginning any analysis, so we + // can load them asynchronously and be sure we know about all + // of them before we start lineage hunting, for + // example. Incidentally, this should also allow people to do + // horrifying things like include a page in a atom. But + // please, if you're reading this: don't. + + // NOTE: sync for now + pattern_assembler.load_pattern_iterative(path.relative(patterns_dir, file), patternlab); + }, + resolve + ); + }); + return promiseAllPatternFiles.then(() => { + // This is the second phase: once we've loaded all patterns, + // start analysis. + // patternlab.patterns.forEach((pattern) => { + // pattern_assembler.process_pattern_iterative(pattern, patternlab); + // }); + return Promise.all(patternlab.patterns.map((pattern) => { + return pattern_assembler.process_pattern_iterative(pattern, patternlab); + })); + }); +} + +function processAllPatternsRecursive(patterns_dir, patternlab) { + diveSync( + patterns_dir, + function (err, file) { + //log any errors + if (err) { + logger.info(err); + return; + } + pattern_assembler.process_pattern_recursive(path.relative(patterns_dir, file), patternlab); + } + ); +} + +/** + * Installs a given plugin. Assumes it has already been pulled down via npm + * @param pluginName - the name of the plugin + */ +function installPlugin(pluginName) { + //get the config + const configPath = path.resolve(process.cwd(), 'patternlab-config.json'); + const config = fs.readJSONSync(path.resolve(configPath), 'utf8'); + const plugin_manager = new pm(config, configPath); + + plugin_manager.install_plugin(pluginName); +} + +/** + * Returns the standardized default config + * + * @return {object} Returns the object representation of the patternlab-config.json + */ +function getDefaultConfig() { + return defaultConfig; +} + +const patternlab_engine = function (config) { + const patternlab = new PatternLab(config); + const paths = patternlab.config.paths; + + function help() { + + logger.info(''); + + logger.info('|=======================================|'); + logger.debug(' Pattern Lab Node Help v' + patternlab.package.version); + logger.info('|=======================================|'); + + logger.info(''); + logger.info('API - usually consumed by an edition'); + logger.info(''); + + logger.debug(' patternlab:build'); + logger.info(' > Compiles the patterns and frontend, outputting to config.paths.public'); + logger.info(''); + + logger.debug(' patternlab:patternsonly'); + logger.info(' > Compiles the patterns only, outputting to config.paths.public'); + logger.info(''); + + logger.debug(' patternlab:version'); + logger.info(' > Return the version of patternlab-node you have installed'); + logger.info(''); + + logger.debug(' patternlab:help'); + logger.info(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.'); + logger.info(''); + + logger.debug(' patternlab:liststarterkits'); + logger.info(' > Returns a url with the list of available starterkits hosted on the Pattern Lab organization Github account'); + logger.info(''); + + logger.debug(' patternlab:loadstarterkit'); + logger.info(' > Load a starterkit into config.paths.source/*'); + logger.info(' > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.'); + logger.info(' > NOTE: In most cases, `npm install starterkit-name` will precede this call.'); + logger.info(' > arguments:'); + logger.info(' -- kit '); + logger.info(' > the name of the starter kit to load'); + logger.info(' -- clean '); + logger.info(' > removes all files from config.paths.source/ prior to load'); + logger.info(' > example (gulp):'); + logger.info(' `gulp patternlab:loadstarterkit --kit=starterkit-mustache-demo`'); + logger.info(''); + + logger.info('==============================='); + logger.info(''); + logger.info('Visit http://patternlab.io/ for more info about Pattern Lab'); + logger.info('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.'); + logger.info('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.'); + logger.info(''); + logger.info('==============================='); + } + function renderSinglePattern(pattern, head) { // Pattern does not need to be built and recompiled more than once if (!pattern.isPattern || pattern.compileState === CompileState.CLEAN) { - return false; + return Promise.resolve(false); } // Allows serializing the compile state @@ -412,8 +512,8 @@ const patternlab_engine = function (config) { try { allData = jsonCopy(patternlab.data, 'config.paths.source.data global data'); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.info('There was an error parsing JSON for ' + pattern.relPath); + logger.info(err); } allData = _.merge(allData, pattern.jsonFileData); allData.cacheBuster = patternlab.cacheBuster; @@ -470,8 +570,8 @@ const patternlab_engine = function (config) { try { allFooterData = jsonCopy(patternlab.data, 'config.paths.source.data global data'); } catch (err) { - console.log('There was an error parsing JSON for ' + pattern.relPath); - console.log(err); + logger.info('There was an error parsing JSON for ' + pattern.relPath); + logger.info(err); } allFooterData = _.merge(allFooterData, pattern.jsonFileData); allFooterData.patternLabFoot = footerPartial; @@ -481,14 +581,15 @@ const patternlab_engine = function (config) { patternlab.events.emit('patternlab-pattern-write-begin', patternlab, pattern); //write the compiled template to the public patterns directory - writePatternFiles(headHTML, pattern, footerHTML); + patternlab.writePatternFiles(headHTML, pattern, footerHTML); patternlab.events.emit('patternlab-pattern-write-end', patternlab, pattern); // Allows serializing the compile state patternlab.graph.node(pattern).compileState = pattern.compileState = CompileState.CLEAN; - plutils.log.info("Built pattern: " + pattern.patternPartial); - return true; + logger.info("Built pattern: " + pattern.patternPartial); + + return Promise.resolve(true); } /** @@ -509,24 +610,27 @@ const patternlab_engine = function (config) { return PatternGraph.loadFromFile(patternlab); } - function buildPatterns(deletePatternDir) { - if (patternlab.config.debug) { - console.log( - chalk.bold('\n====[ Pattern Lab / Node'), - `- v${packageInfo.version}`, - chalk.bold(']====\n') - ); + function cleanBuildDirectory(incrementalBuildsEnabled) { + if (incrementalBuildsEnabled) { + logger.log.info("Incremental builds enabled."); + } else { + // needs to be done BEFORE processing patterns + fs.removeSync(paths.public.patterns); + fs.emptyDirSync(paths.public.patterns); } + } + function buildPatterns(deletePatternDir) { patternlab.events.emit('patternlab-build-pattern-start', patternlab); + // + // CHECK INCREMENTAL BUILD GRAPH + // const graph = patternlab.graph = loadPatternGraph(deletePatternDir); - const graphNeedsUpgrade = !PatternGraph.checkVersion(graph); - if (graphNeedsUpgrade) { - plutils.log.info("Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. " + + logger.log.info("Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. " + "Incremental build is available again on the next successful run."); // Ensure that the freshly built graph has the latest version again. @@ -534,48 +638,14 @@ const patternlab_engine = function (config) { } // Flags - const incrementalBuildsEnabled = !(deletePatternDir || graphNeedsUpgrade); + patternlab.incrementalBuildsEnabled = !(deletePatternDir || graphNeedsUpgrade); - if (incrementalBuildsEnabled) { - plutils.log.info("Incremental builds enabled."); - } else { - // needs to be done BEFORE processing patterns - fs.emptyDirSync(paths.public.patterns); - } + // + // CLEAN BUILD DIRECTORY, maybe + // + cleanBuildDirectory(patternlab.incrementalBuildsEnabled); - try { - patternlab.data = buildPatternData(paths.source.data, fs); - } catch (ex) { - plutils.error('missing or malformed' + paths.source.data + 'data.json Pattern Lab may not work without this file.'); - patternlab.data = {}; - } - try { - patternlab.listitems = dataLoader.loadDataFromFile(path.resolve(paths.source.data, 'listitems'), fs); - } catch (ex) { - plutils.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems file. Pattern Lab may not work without this file.'); - patternlab.listitems = {}; - } - try { - patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles['general-header']), 'utf8'); - patternlab.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles['general-footer']), 'utf8'); - patternlab.patternSection = fs.readFileSync(path.resolve(paths.source.patternlabFiles.patternSection), 'utf8'); - patternlab.patternSectionSubType = fs.readFileSync(path.resolve(paths.source.patternlabFiles.patternSectionSubtype), 'utf8'); - patternlab.viewAll = fs.readFileSync(path.resolve(paths.source.patternlabFiles.viewall), 'utf8'); - } catch (ex) { - console.log(ex); - plutils.error('\nERROR: missing an essential file from ' + paths.source.patternlabFiles + '. Pattern Lab won\'t work without this file.\n'); - process.exit(1); - } - patternlab.patterns = []; - patternlab.subtypePatterns = {}; - patternlab.partials = {}; - patternlab.data.link = {}; - - setCacheBust(); - - pattern_assembler.combine_listItems(patternlab); - - patternlab.events.emit('patternlab-build-global-data-end', patternlab); + patternlab.buildGlobalData(); // diveSync once to perform iterative populating of patternlab object return processAllPatternsIterative(paths.source.patterns, patternlab).then(() => { @@ -592,8 +662,9 @@ const patternlab_engine = function (config) { processAllPatternsRecursive(paths.source.patterns, patternlab); //take the user defined head and foot and process any data and patterns that apply - processHeadPattern(); - processFootPattern(); + // GTP: should these really be invoked from outside? + patternlab.processHeadPattern(); + patternlab.processFootPattern(); //cascade any patternStates lineage_hunter.cascade_pattern_states(patternlab); @@ -619,11 +690,11 @@ const patternlab_engine = function (config) { // rebuild all patterns patternsToBuild = null; - if (incrementalBuildsEnabled) { + if (patternlab.incrementalBuildsEnabled) { // When the graph was loaded from file, some patterns might have been moved/deleted between runs // so the graph data become out of sync patternlab.graph.sync().forEach(n => { - plutils.log.info("[Deleted/Moved] " + n); + logger.log.info("[Deleted/Moved] " + n); }); // TODO Find created or deleted files @@ -639,19 +710,23 @@ const patternlab_engine = function (config) { } //render all patterns last, so lineageR works - patternsToBuild.forEach(pattern => renderSinglePattern(pattern, head)); - - // Saves the pattern graph when all files have been compiled - PatternGraph.storeToFile(patternlab); - if (patternlab.config.exportToGraphViz) { - PatternGraph.exportToDot(patternlab, "dependencyGraph.dot"); - plutils.log.info(`Exported pattern graph to ${path.join(config.paths.public.root, "dependencyGraph.dot")}`); - } + return patternsToBuild + .reduce((previousPromise, pattern) => { + return previousPromise.then(() => renderSinglePattern(pattern, head)); + }, Promise.resolve()) + .then(() => { + // Saves the pattern graph when all files have been compiled + PatternGraph.storeToFile(patternlab); + if (patternlab.config.exportToGraphViz) { + PatternGraph.exportToDot(patternlab, "dependencyGraph.dot"); + logger.log.info(`Exported pattern graph to ${path.join(config.paths.public.root, "dependencyGraph.dot")}`); + } - //export patterns if necessary - pattern_exporter.export_patterns(patternlab); + //export patterns if necessary + pattern_exporter.export_patterns(patternlab); + }); }).catch((err) => { - console.log('Error in buildPatterns():', err); + logger.info('Error in buildPatterns():', err); }); } @@ -662,7 +737,7 @@ const patternlab_engine = function (config) { * @returns {void} current patternlab-node version as defined in package.json, as console output */ version: function () { - return logVersion(); + return patternlab.logVersion(); }, /** @@ -671,19 +746,18 @@ const patternlab_engine = function (config) { * @returns {string} current patternlab-node version as defined in package.json, as string */ v: function () { - return getVersion(); + return patternlab.getVersion(); }, /** * build patterns, copy assets, and construct ui * - * @param {function} callback a function invoked when build is complete * @param {object} options an object used to control build behavior * @returns {Promise} a promise fulfilled when build is complete */ - build: function (callback, options) { + build: function (options) { if (patternlab && patternlab.isBusy) { - console.log('Pattern Lab is busy building a previous run - returning early.'); + logger.info('Pattern Lab is busy building a previous run - returning early.'); return Promise.resolve(); } patternlab.isBusy = true; @@ -695,7 +769,7 @@ const patternlab_engine = function (config) { this.events.on('patternlab-pattern-change', () => { if (!patternlab.isBusy) { options.cleanPublic = false; - return this.build(callback, options); + return this.build(options); } return Promise.resolve(); }); @@ -703,14 +777,12 @@ const patternlab_engine = function (config) { this.events.on('patternlab-global-change', () => { if (!patternlab.isBusy) { options.cleanPublic = true; //rebuild everything - return this.build(callback, options); + return this.build(options); } return Promise.resolve(); }); - printDebug(); patternlab.isBusy = false; - callback(); }); }, @@ -726,20 +798,17 @@ const patternlab_engine = function (config) { /** * build patterns only, leaving existing public files intact * - * @param {function} callback a function invoked when build is complete * @param {object} options an object used to control build behavior * @returns {Promise} a promise fulfilled when build is complete */ - patternsonly: function (callback, options) { + patternsonly: function (options) { if (patternlab && patternlab.isBusy) { - console.log('Pattern Lab is busy building a previous run - returning early.'); + logger.info('Pattern Lab is busy building a previous run - returning early.'); return Promise.resolve(); } patternlab.isBusy = true; return buildPatterns(options.cleanPublic).then(() => { - printDebug(); patternlab.isBusy = false; - callback(); }); }, @@ -749,7 +818,7 @@ const patternlab_engine = function (config) { * @returns {Promise} Returns an Array<{name,url}> for the starterkit repos */ liststarterkits: function () { - return listStarterkits(); + return patternlab.listStarterkits(); }, /** @@ -760,7 +829,7 @@ const patternlab_engine = function (config) { * @returns {void} */ loadstarterkit: function (starterkitName, clean) { - loadStarterKit(starterkitName, clean); + patternlab.loadStarterKit(starterkitName, clean); }, @@ -780,7 +849,7 @@ const patternlab_engine = function (config) { * @returns {Array} all supported file extensions */ getSupportedTemplateExtensions: function () { - return getSupportedTemplateExtensions(); + return patternlab.getSupportedTemplateExtensions(); }, /** @@ -791,7 +860,7 @@ const patternlab_engine = function (config) { */ serve: function (options) { options.watch = true; - return this.build(() => {}, options).then(function () { + return this.build(options).then(function () { serve(patternlab); }); }, @@ -805,5 +874,6 @@ const patternlab_engine = function (config) { patternlab_engine.build_pattern_data = buildPatternData; patternlab_engine.process_all_patterns_iterative = processAllPatternsIterative; patternlab_engine.process_all_patterns_recursive = processAllPatternsRecursive; +patternlab_engine.getDefaultConfig = getDefaultConfig; module.exports = patternlab_engine; diff --git a/core/lib/plugin_manager.js b/core/lib/plugin_manager.js index e636dd4a5..6aa92c9dc 100644 --- a/core/lib/plugin_manager.js +++ b/core/lib/plugin_manager.js @@ -3,7 +3,7 @@ const plugin_manager = function (config, configPath) { const path = require('path'); const fs = require('fs-extra'); - const util = require('./utilities'); + const logger = require('./log'); /** * Loads a plugin @@ -25,12 +25,12 @@ const plugin_manager = function (config, configPath) { const pluginPath = path.resolve( path.join(process.cwd(), 'node_modules', pluginName) ); - console.log('Attempting to load plugin from', pluginPath); + logger.debug(`Attempting to load plugin from ${pluginPath}`); try { var pluginDirStats = fs.statSync(pluginPath); } catch (ex) { - util.error(pluginName + ' not found, please use npm to install it first.'); - util.error(pluginName + ' not loaded.'); + logger.warning(`${pluginName} not found, use npm to install it first.`); + logger.warning(`${pluginName} not loaded.`); return; } const pluginPathDirExists = pluginDirStats.isDirectory(); @@ -63,13 +63,12 @@ const plugin_manager = function (config, configPath) { //write config entry back fs.outputFileSync(path.resolve(configPath), JSON.stringify(diskConfig, null, 2)); - util.debug('Plugin ' + pluginName + ' installed.'); - - //todo, tell them how to uninstall or disable - + logger.info('Plugin ' + pluginName + ' installed.'); + logger.info('Plugin configration added to patternlab-config.json.'); } } catch (ex) { - console.log(ex); + logger.warning(`An error occurred during plugin installation for plugin ${pluginName}`); + logger.warning(ex); } } @@ -91,7 +90,7 @@ const plugin_manager = function (config, configPath) { * Not implemented yet */ function disablePlugin(pluginName) { - console.log('disablePlugin not implemented yet. No change made to state of plugin', pluginName); + logger.warning(`disablePlugin() not implemented yet. No change made to state of plugin ${pluginName}`); } /** @@ -99,7 +98,7 @@ const plugin_manager = function (config, configPath) { * Not implemented yet */ function enablePlugin(pluginName) { - console.log('enablePlugin not implemented yet. No change made to state of plugin', pluginName); + logger.warning(`enablePlugin() not implemented yet. No change made to state of plugin ${pluginName}`); } return { diff --git a/core/lib/pseudopattern_hunter.js b/core/lib/pseudopattern_hunter.js index debae2d8c..78143bdd3 100644 --- a/core/lib/pseudopattern_hunter.js +++ b/core/lib/pseudopattern_hunter.js @@ -7,6 +7,7 @@ const _ = require('lodash'); const lh = require('./lineage_hunter'); const Pattern = require('./object_factory').Pattern; const path = require('path'); +const logger = require('./log'); const lineage_hunter = new lh(); const changes_hunter = new ch(); @@ -29,72 +30,24 @@ pseudopattern_hunter.prototype.find_pseudopatterns = function (currentPattern, p if (pseudoPatterns.length > 0) { for (let i = 0; i < pseudoPatterns.length; i++) { - if (patternlab.config.debug) { - console.log('found pseudoPattern variant of ' + currentPattern.patternPartial); - } - - //we want to do everything we normally would here, except instead read the pseudoPattern data - try { - var variantFileFullPath = path.resolve(paths.source.patterns, pseudoPatterns[i]); - var variantFileData = fs.readJSONSync(variantFileFullPath); - } catch (err) { - console.log('There was an error parsing pseudopattern JSON for ' + currentPattern.relPath); - console.log(err); - } - - //extend any existing data with variant data - variantFileData = _.merge(currentPattern.jsonFileData, variantFileData); - - let variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; - let variantFilePath = path.join(currentPattern.subdir, currentPattern.fileName + '~' + variantName + '.json'); - let lm = fs.statSync(variantFileFullPath); - let patternVariant = Pattern.create(variantFilePath, variantFileData, { - //use the same template as the non-variant - template: currentPattern.template, - fileExtension: currentPattern.fileExtension, - extendedTemplate: currentPattern.extendedTemplate, - isPseudoPattern: true, - basePattern: currentPattern, - stylePartials: currentPattern.stylePartials, - parameteredPartials: currentPattern.parameteredPartials, - - // Only regular patterns are discovered during iterative walks - // Need to recompile on data change or template change - lastModified: Math.max(currentPattern.lastModified, lm.mtime), - - // use the same template engine as the non-variant - engine: currentPattern.engine - }, patternlab); - - changes_hunter.checkBuildState(patternVariant, patternlab); - patternlab.graph.add(patternVariant); - patternlab.graph.link(patternVariant, currentPattern); - - //process the companion markdown file if it exists - pattern_assembler.parse_pattern_markdown(patternVariant, patternlab); - - //find pattern lineage - lineage_hunter.find_lineage(patternVariant, patternlab); - - //add to patternlab object so we can look these up later. - pattern_assembler.addPattern(patternVariant, patternlab); + logger.debug(`Found pseudoPattern variant of ${currentPattern.patternPartial}`); //we want to do everything we normally would here, except instead read the pseudoPattern data try { var variantFileFullPath = path.resolve(paths.source.patterns, pseudoPatterns[i]); var variantFileData = fs.readJSONSync(variantFileFullPath); } catch (err) { - console.log('There was an error parsing pseudopattern JSON for ' + currentPattern.relPath); - console.log(err); + logger.warning(`There was an error parsing pseudopattern JSON for ${currentPattern.relPath}`); + logger.warning(err); } //extend any existing data with variant data - variantFileData = _.merge(currentPattern.jsonFileData, variantFileData); + variantFileData = _.merge({}, currentPattern.jsonFileData, variantFileData); - variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; - variantFilePath = path.join(currentPattern.subdir, currentPattern.fileName + '~' + variantName + '.json'); - lm = fs.statSync(variantFileFullPath); - patternVariant = Pattern.create(variantFilePath, variantFileData, { + const variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; + const variantFilePath = path.join(currentPattern.subdir, currentPattern.fileName + '~' + variantName + '.json'); + const lm = fs.statSync(variantFileFullPath); + const patternVariant = Pattern.create(variantFilePath, variantFileData, { //use the same template as the non-variant template: currentPattern.template, fileExtension: currentPattern.fileExtension, diff --git a/core/lib/serve.js b/core/lib/serve.js index a773acde9..3b1b42074 100644 --- a/core/lib/serve.js +++ b/core/lib/serve.js @@ -1,6 +1,7 @@ "use strict"; const path = require('path'); -const liveServer = require('live-server'); +const liveServer = require('@pattern-lab/live-server'); +const logger = require('./log'); const serve = (patternlab) => { @@ -11,7 +12,8 @@ const serve = (patternlab) => { ignore: path.join(path.resolve(patternlab.config.paths.public.root)), file: 'index.html', logLevel: 0, // errors only - wait: 1000 + wait: 1000, + port: 3000 }; // allow for overrides should they exist inside patternlab-config.json @@ -34,6 +36,8 @@ const serve = (patternlab) => { //start! liveServer.start(liveServerConfig); + logger.info(`Pattern Lab is being served from http://127.0.0.1:${liveServerConfig.port}`); + }; module.exports = serve; diff --git a/core/lib/starterkit_manager.js b/core/lib/starterkit_manager.js index 2498580b9..b6535572d 100644 --- a/core/lib/starterkit_manager.js +++ b/core/lib/starterkit_manager.js @@ -4,7 +4,7 @@ const starterkit_manager = function (config) { const path = require('path'); const fetch = require('node-fetch'); const fs = require('fs-extra'); - const util = require('./utilities'); + const logger = require('./log'); const paths = config.paths; /** @@ -18,34 +18,35 @@ const starterkit_manager = function (config) { const kitPath = path.resolve( path.join(process.cwd(), 'node_modules', starterkitName, config.starterkitSubDir) ); - console.log('Attempting to load starterkit from', kitPath); + logger.debug('Attempting to load starterkit from', kitPath); try { var kitDirStats = fs.statSync(kitPath); } catch (ex) { - util.error(starterkitName + ' not found, please use npm to install it first.'); - util.error(starterkitName + ' not loaded.'); + logger.warning(`${starterkitName} not found, use npm to install it first.`); + logger.warning(`${starterkitName} not loaded.`); return; } const kitPathDirExists = kitDirStats.isDirectory(); if (kitPathDirExists) { if (clean) { - console.log('Deleting contents of', paths.source.root, 'prior to starterkit load.'); + logger.info(`Deleting contents of ${paths.source.root} prior to starterkit load.`); fs.emptyDirSync(paths.source.root); } else { - console.log('Overwriting contents of', paths.source.root, 'during starterkit load.'); + logger.info(`Overwriting contents of ${paths.source.root} during starterkit load.`); } try { fs.copySync(kitPath, paths.source.root); } catch (ex) { - util.error(ex); + logger.error(ex); return; } - util.debug('starterkit ' + starterkitName + ' loaded successfully.'); + logger.info('Starterkit ' + starterkitName + ' loaded into source/.'); } } catch (ex) { - console.log(ex); + logger.warning(`An error occurred during starterkit installation for starterkit ${starterkitName}`); + logger.warning(ex); } } @@ -75,7 +76,7 @@ const starterkit_manager = function (config) { return {name: repo.name, url: repo.html_url}; }); }).catch(function (err) { - console.error(err); + logger.error(err); return false; }); } diff --git a/core/lib/style_modifier_hunter.js b/core/lib/style_modifier_hunter.js index af50fb155..c58f9e37a 100644 --- a/core/lib/style_modifier_hunter.js +++ b/core/lib/style_modifier_hunter.js @@ -1,5 +1,7 @@ "use strict"; +const logger = require('./log'); + const style_modifier_hunter = function () { /** @@ -17,9 +19,7 @@ const style_modifier_hunter = function () { //replace the special character pipe | used to separate multiple classes with a space styleModifier = styleModifier.replace(/\|/g, ' '); - if (patternlab.config.debug) { - console.log('found partial styleModifier within pattern ' + pattern.patternPartial); - } + logger.debug(`Found partial styleModifier within pattern ${pattern.patternPartial}`); //replace the stylemodifier placeholder with the class name pattern.extendedTemplate = pattern.extendedTemplate.replace(/{{[ ]?styleModifier[ ]?}}/i, styleModifier); diff --git a/core/lib/ui_builder.js b/core/lib/ui_builder.js index 6c2807467..8bb287775 100644 --- a/core/lib/ui_builder.js +++ b/core/lib/ui_builder.js @@ -5,7 +5,7 @@ const jsonCopy = require('./json_copy'); const ae = require('./annotation_exporter'); const of = require('./object_factory'); const Pattern = of.Pattern; -const plutils = require('./utilities'); +const logger = require('./log'); const eol = require('os').EOL; const _ = require('lodash'); @@ -67,18 +67,14 @@ const ui_builder = function () { // skip underscore-prefixed files isOmitted = pattern.isPattern && pattern.fileName.charAt(0) === '_'; if (isOmitted) { - if (patternlab.config.debug) { - console.log('Omitting ' + pattern.patternPartial + " from styleguide patterns because it has an underscore suffix."); - } + logger.debug(`Omitting ${pattern.patternPartial} from styleguide patterns because it has an underscore suffix.`); return true; } //this is meant to be a homepage that is not present anywhere else isOmitted = pattern.patternPartial === patternlab.config.defaultPattern; if (isOmitted) { - if (patternlab.config.debug) { - console.log('Omitting ' + pattern.patternPartial + ' from styleguide patterns because it is defined as a defaultPattern.'); - } + logger.debug(`Omitting ${pattern.patternPartial} from styleguide patterns because it is defined as a defaultPattern.`); patternlab.defaultPattern = pattern; return true; } @@ -86,18 +82,14 @@ const ui_builder = function () { //this pattern is contained with a directory prefixed with an underscore (a handy way to hide whole directories from the nav isOmitted = pattern.relPath.charAt(0) === '_' || pattern.relPath.indexOf(path.sep + '_') > -1; if (isOmitted) { - if (patternlab.config.debug) { - console.log('Omitting ' + pattern.patternPartial + ' from styleguide patterns because its contained within an underscored directory.'); - } + logger.debug(`Omitting ${pattern.patternPartial} from styleguide patterns because its contained within an underscored directory.`); return true; } //this pattern is a head or foot pattern isOmitted = pattern.isMetaPattern; if (isOmitted) { - if (patternlab.config.debug) { - console.log('Omitting ' + pattern.patternPartial + ' from styleguide patterns because its a meta pattern.'); - } + logger.debug(`Omitting ${pattern.patternPartial} from styleguide patterns because its a meta pattern.`); return true; } @@ -169,9 +161,7 @@ const ui_builder = function () { const patternType = _.find(patternlab.patternTypes, ['patternType', pattern.patternType]); if (!patternType) { - plutils.error('Could not find patternType' + pattern.patternType + '. This is a critical error.'); - console.trace(); - process.exit(1); + logger.error(`Could not find patternType ${pattern.patternType}. This is a critical error.`); } return patternType; @@ -188,9 +178,7 @@ const ui_builder = function () { const patternSubType = _.find(patternType.patternTypeItems, ['patternSubtype', pattern.patternSubType]); if (!patternSubType) { - plutils.error('Could not find patternType ' + pattern.patternType + '-' + pattern.patternType + '. This is a critical error.'); - console.trace(); - process.exit(1); + logger.error(`Could not find patternType ${pattern.patternType}-${pattern.patternType}. This is a critical error.`); } return patternSubType; @@ -276,9 +264,7 @@ const ui_builder = function () { function addPatternItem(patternlab, pattern, isViewAllVariant) { const patternType = getPatternType(patternlab, pattern); if (!patternType) { - plutils.error('Could not find patternType' + pattern.patternType + '. This is a critical error.'); - console.trace(); - process.exit(1); + logger.error(`Could not find patternType ${pattern.patternType}. This is a critical error.`); } if (!patternType.patternItems) { @@ -439,8 +425,8 @@ const ui_builder = function () { try { allFooterData = jsonCopy(patternlab.data, 'config.paths.source.data plus patterns data'); } catch (err) { - console.log('There was an error parsing JSON for patternlab.data'); - console.log(err); + logger.warning('There was an error parsing JSON for patternlab.data'); + logger.warning(err); } allFooterData.patternLabFoot = footerPartial; @@ -517,9 +503,7 @@ const ui_builder = function () { return exclude === patternType + '/' + patternSubtype; }); if (omitPatternType) { - if (patternlab.config.debug) { - console.log('Omitting ' + patternType + '/' + patternSubtype + ' from building a viewall page because its patternSubGroup is specified in styleguideExcludes.'); - } + logger.debug(`Omitting ${patternType}/${patternSubtype} from building a viewall page because its patternSubGroup is specified in styleguideExcludes.`); } else { styleguideTypePatterns = styleguideTypePatterns.concat(subtypePatterns); } @@ -556,9 +540,7 @@ const ui_builder = function () { return exclude === patternType; }); if (omitPatternType) { - if (patternlab.config.debug) { - console.log('Omitting ' + patternType + ' from building a viewall page because its patternGroup is specified in styleguideExcludes.'); - } + logger.debug(`Omitting ${patternType} from building a viewall page because its patternGroup is specified in styleguideExcludes.`); } else { patterns = patterns.concat(styleguideTypePatterns); } @@ -671,10 +653,8 @@ const ui_builder = function () { let patternlabSiteHtml; try { patternlabSiteHtml = fs.readFileSync(path.resolve(paths.source.styleguide, 'index.html'), 'utf8'); - } catch (error) { - console.log(error); - console.log("\nERROR: Could not load one or more styleguidekit assets from", paths.source.styleguide, '\n'); - process.exit(1); + } catch (err) { + logger.error(`Could not load one or more styleguidekit assets from ${paths.source.styleguide}`); } fs.outputFileSync(path.resolve(paths.public.root, 'index.html'), patternlabSiteHtml); diff --git a/package-lock.json b/package-lock.json index 8db5e864b..c0f0e6171 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,45 @@ { "name": "@pattern-lab/patternlab-node", - "version": "3.0.0-alpha.1", + "version": "3.0.0-alpha.4", "lockfileVersion": 1, "requires": true, "dependencies": { + "@pattern-lab/live-server": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@pattern-lab/live-server/-/live-server-1.3.2.tgz", + "integrity": "sha512-Ka1e+1DclAZHGSFLcmj3+ZA7R1rXcHEzBf34kYi+x3Jtf6yaNZASIVfa8nxaru5/82EbjHKVNpYK4J+NmZakHw==", + "requires": { + "chokidar": "1.7.0", + "colors": "1.1.2", + "connect": "3.6.5", + "cors": "2.8.4", + "event-stream": "3.3.4", + "faye-websocket": "0.11.1", + "http-auth": "3.2.3", + "morgan": "1.9.0", + "object-assign": "4.1.1", + "opn": "5.1.0", + "proxy-middleware": "0.15.0", + "send": "0.16.1", + "serve-index": "1.9.1" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "@pattern-lab/patternengine-node-mustache": { + "version": "2.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@pattern-lab/patternengine-node-mustache/-/patternengine-node-mustache-2.0.0-alpha.1.tgz", + "integrity": "sha512-DVtGDv0zk2eGRFhdv1EBv6XY0rKCiD/t0bIiHpBBeIHI/vgHrC888FOrmY2Iq4jb3WLSjD66AE2Vhdt9QGWueg==", + "requires": { + "fs-extra": "0.30.0", + "mustache": "2.3.0" + } + }, "accepts": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", @@ -229,14 +265,14 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "connect": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.5.1.tgz", - "integrity": "sha1-bTDXpjx/FwhXprOqazY9lz3KWI4=", + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", + "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=", "requires": { - "debug": "2.2.0", - "finalhandler": "0.5.1", + "debug": "2.6.9", + "finalhandler": "1.0.6", "parseurl": "1.3.2", - "utils-merge": "1.0.0" + "utils-merge": "1.0.1" } }, "core-util-is": { @@ -261,11 +297,11 @@ } }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "0.7.1" + "ms": "2.0.0" } }, "del": { @@ -1418,13 +1454,15 @@ } }, "finalhandler": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz", - "integrity": "sha1-LEANjUUwk1vCMlScX6OF7Afeb80=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", "requires": { - "debug": "2.2.0", + "debug": "2.6.9", + "encodeurl": "1.0.1", "escape-html": "1.0.3", "on-finished": "2.3.0", + "parseurl": "1.3.2", "statuses": "1.3.1", "unpipe": "1.0.0" } @@ -1652,9 +1690,9 @@ } }, "http-auth": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.1.3.tgz", - "integrity": "sha1-lFz63WZSHq+PfISRPTd9exXyTjE=", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.2.3.tgz", + "integrity": "sha1-Y2hCtx1uHyyY26Ca9UQXof74thw=", "requires": { "apache-crypt": "1.2.1", "apache-md5": "1.1.2", @@ -1898,31 +1936,6 @@ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz" } }, - "live-server": { - "version": "github:pattern-lab/live-server#d46ec211455efb0ae2ad140b09e151bc2649c496", - "requires": { - "chokidar": "1.7.0", - "colors": "1.1.2", - "connect": "3.5.1", - "cors": "2.8.4", - "event-stream": "3.3.4", - "faye-websocket": "0.11.1", - "http-auth": "3.1.3", - "morgan": "1.9.0", - "object-assign": "4.1.1", - "opn": "5.1.0", - "proxy-middleware": "0.15.0", - "send": "0.16.1", - "serve-index": "1.9.1" - }, - "dependencies": { - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - } - } - }, "lodash": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz", @@ -2078,27 +2091,17 @@ "depd": "1.1.1", "on-finished": "2.3.0", "on-headers": "1.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mustache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", + "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" }, "mz": { "version": "2.7.0", @@ -2424,21 +2427,6 @@ "on-finished": "2.3.0", "range-parser": "1.2.0", "statuses": "1.3.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "serve-index": { @@ -2453,21 +2441,6 @@ "http-errors": "1.6.2", "mime-types": "2.1.17", "parseurl": "1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "set-immediate-shim": { @@ -5331,9 +5304,9 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { "version": "3.1.0", diff --git a/package.json b/package.json index 9dc29ce10..72bbcf04e 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,11 @@ { "name": "@pattern-lab/patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "3.0.0-alpha.4", + "version": "3.0.0-alpha.5", "main": "./core/lib/patternlab.js", "dependencies": { + "@pattern-lab/live-server": "^1.3.2", + "@pattern-lab/patternengine-node-mustache": "^2.0.0-alpha.1", "async": "^2.1.2", "chalk": "^1.1.3", "chokidar": "^1.7.0", @@ -15,7 +17,6 @@ "graphlib": "^2.1.1", "js-beautify": "^1.6.3", "js-yaml": "^3.6.1", - "live-server": "github:pattern-lab/live-server#d46ec21", "lodash": "~4.13.1", "markdown-it": "^6.0.1", "node-fetch": "^1.6.0", diff --git a/patternlab-config.json b/patternlab-config.json index dc3021cc6..7c37b30a8 100644 --- a/patternlab-config.json +++ b/patternlab-config.json @@ -1,35 +1,8 @@ { - "paths" : { - "source" : { - "root": "./source/", - "patterns" : "./source/_patterns/", - "data" : "./source/_data/", - "styleguide" : "./core/styleguide/", - "patternlabFiles" : "./core/", - "js" : "./source/js", - "images" : "./source/images", - "fonts" : "./source/fonts", - "css" : "./source/css/" - }, - "public" : { - "root" : "./public/", - "patterns" : "./public/patterns/", - "data" : "./public/data/", - "styleguide" : "./public/styleguide/", - "js" : "./public/js", - "images" : "./public/images", - "fonts" : "./public/fonts", - "css" : "./public/css" - } - }, - "styleGuideExcludes": [ - "templates", - "pages" - ], + "cacheBust": true, + "cleanPublic" : true, "defaultPattern": "all", - "ignored-extensions" : ["scss", "DS_Store", "less"], - "ignored-directories" : ["scss"], - "debug": false, + "defaultShowPatternInfo": false, "ishControlsHide": { "s": false, "m": false, @@ -52,17 +25,54 @@ "m": [500, 800], "l": [800, 2600] }, - "patternStateCascade": ["inprogress", "inreview", "complete"], - "patternExportPatternPartials": [], - "patternExportDirectory": "./pattern_exports/", - "cacheBust": true, + "logLevel": "info", "outputFileSuffixes": { "rendered": ".rendered", "rawTemplate": "", "markupOnly": ".markup-only" }, - "cleanOutputHtml": true, - "exportToGraphViz": false, + "paths" : { + "source" : { + "root": "./source/", + "patterns" : "./source/_patterns/", + "data" : "./source/_data/", + "meta": "./source/_meta/", + "annotations" : "./source/_annotations/", + "styleguide" : "./node_modules/@pattern-lab/styleguidekit-assets-default/dist/", + "patternlabFiles" : { + "general-header": "./node_modules/@pattern-lab/styleguidekit-mustache-default/views/partials/general-header.mustache", + "general-footer": "./node_modules/@pattern-lab/styleguidekit-mustache-default/views/partials/general-footer.mustache", + "patternSection": "./node_modules/@pattern-lab/styleguidekit-mustache-default/views/partials/patternSection.mustache", + "patternSectionSubtype": "./node_modules/@pattern-lab/styleguidekit-mustache-default/views/partials/patternSectionSubtype.mustache", + "viewall": "./node_modules/@pattern-lab/styleguidekit-mustache-default/views/viewall.mustache" + }, + "js" : "./source/js", + "images" : "./source/images", + "fonts" : "./source/fonts", + "css" : "./source/css/" + }, + "public" : { + "root" : "./public/", + "patterns" : "./public/patterns/", + "data" : "./public/styleguide/data/", + "annotations" : "./public/annotations/", + "styleguide" : "./public/styleguide/", + "js" : "./public/js", + "images" : "./public/images", + "fonts" : "./public/fonts", + "css" : "./public/css" + } + }, + "patternExtension": "mustache", + "patternStateCascade": ["inprogress", "inreview", "complete"], + "patternExportDirectory": "./pattern_exports/", + "patternExportPatternPartials": [], + "serverOptions": { + "wait": 1000 + }, + "starterkitSubDir": "dist", + "styleGuideExcludes": [ + ], "theme": { "color": "dark", "density": "compact", diff --git a/test/asset_copy_tests.js b/test/asset_copy_tests.js index 9d2346912..d3865817b 100644 --- a/test/asset_copy_tests.js +++ b/test/asset_copy_tests.js @@ -38,7 +38,7 @@ function createFakePatternLab(customProps) { } }, styleGuideExcludes: [ ], - debug: false, + logLevel: 'quiet', outputFileSuffixes: { rendered: '.rendered', rawTemplate: '', diff --git a/test/files/_patterns/00-test/03-styled-atom.json b/test/files/_patterns/00-test/03-styled-atom.json new file mode 100644 index 000000000..475247e1a --- /dev/null +++ b/test/files/_patterns/00-test/03-styled-atom.json @@ -0,0 +1,3 @@ +{ + "message": "baseMessage" +} diff --git a/test/lineage_hunter_tests.js b/test/lineage_hunter_tests.js index 58d7892c6..cf87a6b04 100644 --- a/test/lineage_hunter_tests.js +++ b/test/lineage_hunter_tests.js @@ -49,7 +49,7 @@ function createBasePatternLabObject() { }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; pl.patternGroups = {}; diff --git a/test/list_item_hunter_tests.js b/test/list_item_hunter_tests.js index ff7dae374..36eb16a0b 100644 --- a/test/list_item_hunter_tests.js +++ b/test/list_item_hunter_tests.js @@ -66,7 +66,7 @@ function createFakePatternLab(customProps) { "partials": [] }, "config": { - "debug": false, + "logLevel": 'quiet', "paths": { "source": { "patterns": "./test/files/_patterns" @@ -344,7 +344,7 @@ tap.test('process_list_item_partials - correctly ignores bookended partials with pl.config = {}; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; pl.config.patterns = { source: patterns_dir }; diff --git a/test/parameter_hunter_tests.js b/test/parameter_hunter_tests.js index 05823fd30..40049a4a1 100644 --- a/test/parameter_hunter_tests.js +++ b/test/parameter_hunter_tests.js @@ -56,7 +56,7 @@ function patternlabClosure() { } ], config: { - debug: false + logLevel: 'quiet' }, data: { description: 'Not a quote from a smart man', diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index fe35e6fb6..63a073ba7 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -93,7 +93,7 @@ tap.test('processPatternRecursive - correctly replaces all stylemodifiers when m }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -137,7 +137,7 @@ tap.test('processPatternRecursive - correctly replaces multiple stylemodifier cl }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -182,7 +182,7 @@ tap.test('processPatternRecursive - correctly ignores a partial without a style }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -225,7 +225,7 @@ tap.test('processPatternRecursive - correctly ignores bookended partials without }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -269,7 +269,7 @@ tap.test('processPatternRecursive - correctly ignores a partial without a style }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -314,7 +314,7 @@ tap.test('processPatternRecursive - correctly ignores bookended partials without }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -359,7 +359,7 @@ tap.test('processPatternRecursive - does not pollute previous patterns when a la }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -413,7 +413,7 @@ tap.test('processPatternRecursive - ensure deep-nesting works', function(test) { }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; @@ -611,7 +611,7 @@ tap.test('addPattern - adds pattern extended template to patternlab partial obje patternlab.patterns = []; patternlab.partials = {}; patternlab.data = {link: {}}; - patternlab.config = {debug: false}; + patternlab.config = {logLevel: 'quiet'}; patternlab.config.outputFileSuffixes = {rendered: ''}; var pattern = new Pattern('00-test/01-bar.mustache'); @@ -635,7 +635,7 @@ tap.test('addPattern - adds pattern template to patternlab partial object if ext patternlab.patterns = []; patternlab.partials = {}; patternlab.data = {link: {}}; - patternlab.config = { debug: false }; + patternlab.config = { logLevel: 'quiet' }; patternlab.config.outputFileSuffixes = {rendered : ''}; var pattern = new Pattern('00-test/01-bar.mustache'); @@ -699,7 +699,7 @@ tap.test('markModifiedPatterns - finds patterns when modification date is missin var patternlab = emptyPatternLab(); patternlab.partials = {}; patternlab.data = {link: {}}; - patternlab.config = { debug: false }; + patternlab.config = { logLevel: 'quiet' }; patternlab.config.outputFileSuffixes = {rendered : ''}; var pattern = new Pattern('00-test/01-bar.mustache'); @@ -720,7 +720,7 @@ tap.test('markModifiedPatterns - finds patterns via compile state', function(tes var patternlab = emptyPatternLab(); patternlab.partials = {}; patternlab.data = {link: {}}; - patternlab.config = { debug: false }; + patternlab.config = { logLevel: 'quiet' }; patternlab.config.outputFileSuffixes = {rendered : ''}; var pattern = new Pattern('00-test/01-bar.mustache'); diff --git a/test/patternlab_tests.js b/test/patternlab_tests.js index c680058ba..698830463 100644 --- a/test/patternlab_tests.js +++ b/test/patternlab_tests.js @@ -4,6 +4,7 @@ const tap = require('tap'); const rewire = require("rewire"); const _ = require('lodash'); const fs = require('fs-extra'); +const defaultConfig = require('../patternlab-config.json'); var config = require('./util/patternlab-config.json'); var plEngineModule = rewire('../core/lib/patternlab'); @@ -67,9 +68,9 @@ tap.test('buildPatterns - should replace data link even when pattern parameter p var pl = new plEngineModule(config); //act - pl.build(function() { + pl.build(true).then(() => { test.end(); - }, true); + }); }); tap.test('buildPatternData - can load json, yaml, and yml files', function(test) { @@ -81,3 +82,10 @@ tap.test('buildPatternData - can load json, yaml, and yml files', function(test) test.equals(dataResult.from_json, "from_json"); test.end(); }); + +tap.test('getDefaultConfig - should return the default config object', function(test) { + const requestedConfig = plEngineModule.getDefaultConfig(); + test.type(requestedConfig, 'object'); + test.equals(requestedConfig, defaultConfig); + test.end(); +}); diff --git a/test/pseudopattern_hunter_tests.js b/test/pseudopattern_hunter_tests.js index 57becf357..3515624c2 100644 --- a/test/pseudopattern_hunter_tests.js +++ b/test/pseudopattern_hunter_tests.js @@ -33,7 +33,7 @@ function stubPatternlab() { }; pl.data = {}; pl.data.link = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; pl.patterns = []; pl.partials = {}; pl.config.patternStates = {}; @@ -46,11 +46,7 @@ tap.test('pseudpattern found and added as a pattern', function (test) { //arrange var pl = stubPatternlab(); - var atomPattern = new Pattern('00-test/03-styled-atom.mustache'); - atomPattern.template = fs.readFileSync(patterns_dir + '00-test/03-styled-atom.mustache', 'utf8'); - atomPattern.extendedTemplate = atomPattern.template; - atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); - + var atomPattern = pattern_assembler.load_pattern_iterative('00-test/03-styled-atom.mustache', pl); pattern_assembler.addPattern(atomPattern, pl); //act @@ -59,12 +55,27 @@ tap.test('pseudpattern found and added as a pattern', function (test) { //assert test.equals(patternCountBefore + 1, pl.patterns.length); test.equals(pl.patterns[1].patternPartial, 'test-styled-atom-alt'); - test.equals(pl.patterns[1].extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), ' {{message}} '); test.equals(JSON.stringify(pl.patterns[1].jsonFileData), JSON.stringify({"message": "alternateMessage"})); test.equals(pl.patterns[1].patternLink, '00-test-03-styled-atom-alt' + path.sep + '00-test-03-styled-atom-alt.html'); }); }); +tap.test('pseudpattern does not pollute base pattern data', function (test) { + //arrange + var pl = stubPatternlab(); + + var atomPattern = pattern_assembler.load_pattern_iterative('00-test/03-styled-atom.mustache', pl); + pattern_assembler.addPattern(atomPattern, pl); + + //act + var patternCountBefore = pl.patterns.length; + return pph.find_pseudopatterns(atomPattern, pl).then(() => { + //assert + test.equals(pl.patterns[0].patternPartial, 'test-styled-atom'); + test.equals(JSON.stringify(pl.patterns[0].jsonFileData), JSON.stringify({"message": "baseMessage"})); + }); +}); + tap.test('pseudpattern variant includes stylePartials and parameteredPartials', function (test) { //arrange var pl = stubPatternlab(); diff --git a/test/style_modifier_hunter_tests.js b/test/style_modifier_hunter_tests.js index e1a999a8b..2d3e25df0 100644 --- a/test/style_modifier_hunter_tests.js +++ b/test/style_modifier_hunter_tests.js @@ -9,7 +9,7 @@ tap.test('uses the partial stylemodifer to modify the patterns extendedTemplate' var pl = {}; pl.partials = {}; pl.config = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; var pattern = { extendedTemplate: '
' @@ -30,7 +30,7 @@ tap.test('replaces style modifiers with spaces in the syntax', function(test){ var pl = {}; pl.partials = {}; pl.config = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; var pattern = { extendedTemplate: '
' @@ -51,7 +51,7 @@ tap.test('replaces multiple style modifiers', function(test){ var pl = {}; pl.partials = {}; pl.config = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; var pattern = { extendedTemplate: '
' @@ -72,7 +72,7 @@ tap.test('does not alter pattern extendedTemplate if styleModifier not found in var pl = {}; pl.partials = {}; pl.config = {}; - pl.config.debug = false; + pl.config.logLevel = 'quiet'; var pattern = { extendedTemplate: '
' diff --git a/test/ui_builder_tests.js b/test/ui_builder_tests.js index 6dc5bf308..8e563d71c 100644 --- a/test/ui_builder_tests.js +++ b/test/ui_builder_tests.js @@ -42,7 +42,7 @@ function createFakePatternLab(customProps) { } }, styleGuideExcludes: [ 'templates' ], - debug: false, + logLevel: 'quiet', outputFileSuffixes: { rendered: '.rendered', rawTemplate: '', diff --git a/test/util/patternlab-config.json b/test/util/patternlab-config.json index 720975302..2029bccfe 100644 --- a/test/util/patternlab-config.json +++ b/test/util/patternlab-config.json @@ -36,7 +36,7 @@ "defaultPattern": "all", "ignored-extensions" : ["scss", "DS_Store", "less"], "ignored-directories" : ["scss"], - "debug": false, + "logLevel": "quiet", "ishControlsHide": { "s": false, "m": false,