diff --git a/core/lib/data_loader.js b/core/lib/data_loader.js new file mode 100644 index 000000000..a91911f3e --- /dev/null +++ b/core/lib/data_loader.js @@ -0,0 +1,63 @@ +"use strict"; + +const glob = require('glob'), + _ = require('lodash'), + path = require('path'), + yaml = require('js-yaml'); + +/** + * Loads a single config file, in yaml/json format. + * + * @param dataFilesPath - leave off the file extension. + * @param fsDep + * @returns {*} + */ +function loadFile(dataFilesPath, fsDep) { + const dataFilesFullPath = dataFilesPath + '*.{json,yml,yaml}'; + + if (dataFilesPath) { + const dataFiles = glob.sync(dataFilesFullPath), + dataFile = _.head(dataFiles); + + if (dataFile && fsDep.existsSync(path.resolve(dataFile))) { + return yaml.safeLoad(fsDep.readFileSync(path.resolve(dataFile), 'utf8')); + } + } + + return null; +} + +/** + * Loads a set of config files from a folder, in yaml/json format. + * + * @param dataFilesPath - leave off the file extension + * @param excludeFileNames - leave off the file extension + * @param fsDep + * @returns Object, with merged data files, empty object if no files. + */ +function loadDataFromFolder(dataFilesPath, excludeFileNames, fsDep) { + const dataFilesFullPath = dataFilesPath + '*.{json,yml,yaml}', + excludeFullPath = dataFilesPath + excludeFileNames + '.{json,yml,yaml}'; + + let globOptions = {}; + if (excludeFileNames) { + globOptions.ignore = [excludeFullPath]; + } + + const dataFiles = glob.sync(dataFilesFullPath, globOptions); + let mergeObject = {}; + + dataFiles.forEach(function (filePath) { + let jsonData = yaml.safeLoad(fsDep.readFileSync(path.resolve(filePath), 'utf8')); + mergeObject = _.merge(mergeObject, jsonData); + }); + + return mergeObject; +} + +module.exports = function configFileLoader() { + return { + loadDataFromFile: loadFile, + loadDataFromFolder: loadDataFromFolder + }; +}; diff --git a/core/lib/pattern_assembler.js b/core/lib/pattern_assembler.js index b85867d88..02f0dad13 100644 --- a/core/lib/pattern_assembler.js +++ b/core/lib/pattern_assembler.js @@ -8,6 +8,7 @@ var path = require('path'), pph = require('./pseudopattern_hunter'), mp = require('./markdown_parser'), plutils = require('./utilities'), + dataLoader = require('./data_loader')(), patternEngines = require('./pattern_engines'), lh = require('./lineage_hunter'), lih = require('./list_item_hunter'), @@ -318,16 +319,13 @@ var pattern_assembler = function () { //look for a json file for this template try { - var jsonFilename = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".json"); - try { - var jsonFilenameStats = fs.statSync(jsonFilename); - } catch (err) { - //not a file - } - if (jsonFilenameStats && jsonFilenameStats.isFile()) { - currentPattern.jsonFileData = fs.readJSONSync(jsonFilename); + var jsonFilename = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName); + let configData = dataLoader.loadDataFromFile(jsonFilename, fs); + + if (configData) { + currentPattern.jsonFileData = configData; if (patternlab.config.debug) { - console.log('processPatternIterative: found pattern-specific data.json for ' + currentPattern.patternPartial); + console.log('processPatternIterative: found pattern-specific config data for ' + currentPattern.patternPartial); } } } @@ -338,17 +336,14 @@ var pattern_assembler = function () { //look for a listitems.json file for this template try { - var listJsonFileName = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".listitems.json"); - try { - var listJsonFileStats = fs.statSync(listJsonFileName); - } catch (err) { - //not a file - } - if (listJsonFileStats && listJsonFileStats.isFile()) { - currentPattern.listitems = fs.readJSONSync(listJsonFileName); + var listJsonFileName = path.resolve(patternsPath, currentPattern.subdir, currentPattern.fileName + ".listitems"); + let listItemsConfig = dataLoader.loadDataFromFile(listJsonFileName, fs); + + if (listItemsConfig) { + currentPattern.listitems = listItemsConfig; buildListItems(currentPattern); if (patternlab.config.debug) { - console.log('found pattern-specific listitems.json for ' + currentPattern.patternPartial); + console.log('found pattern-specific listitems config for ' + currentPattern.patternPartial); } } } diff --git a/core/lib/patternlab.js b/core/lib/patternlab.js index f6d6bbffc..942880312 100644 --- a/core/lib/patternlab.js +++ b/core/lib/patternlab.js @@ -11,7 +11,6 @@ "use strict"; var diveSync = require('diveSync'), - glob = require('glob'), _ = require('lodash'), path = require('path'), chalk = require('chalk'), @@ -20,6 +19,7 @@ var diveSync = require('diveSync'), pm = require('./plugin_manager'), fs = require('fs-extra'), packageInfo = require('../../package.json'), + dataLoader = require('./data_loader')(), plutils = require('./utilities'), PatternGraph = require('./pattern_graph').PatternGraph; @@ -38,14 +38,14 @@ console.log( var patternEngines = require('./pattern_engines'); var EventEmitter = require('events').EventEmitter; +/** + * Given a path, load info from the folder to compile into a single config object. + * @param dataFilesPath + * @param fsDep + * @returns {{}} + */ function buildPatternData(dataFilesPath, fsDep) { - var dataFiles = glob.sync(dataFilesPath + '*.json', {"ignore" : [dataFilesPath + 'listitems.json']}); - var mergeObject = {}; - dataFiles.forEach(function (filePath) { - var jsonData = fsDep.readJSONSync(path.resolve(filePath), 'utf8'); - mergeObject = _.merge(mergeObject, jsonData); - }); - return mergeObject; + return dataLoader.loadDataFromFolder(dataFilesPath, 'listitems', fsDep); } // GTP: these two diveSync pattern processors factored out so they can be reused @@ -492,9 +492,9 @@ var patternlab_engine = function (config) { patternlab.data = {}; } try { - patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json')); + patternlab.listitems = dataLoader.loadDataFromFile(path.resolve(paths.source.data, 'listitems.{json,yml,yaml}')); } catch (ex) { - plutils.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems.json file. Pattern Lab may not work without this file.'); + plutils.warning('WARNING: missing or malformed ' + paths.source.data + 'listitems file. Pattern Lab may not work without this file.'); patternlab.listitems = {}; } try { diff --git a/test/data_loader_tests.js b/test/data_loader_tests.js new file mode 100644 index 000000000..3be872e76 --- /dev/null +++ b/test/data_loader_tests.js @@ -0,0 +1,13 @@ +'use strict'; + +const tap = require('tap'); + +tap.test('loadDataFromFile - Load ', function(test){ + const fs = require('fs-extra'), + dataLoader = require('../core/lib/data_loader')(), + data_dir = './test/files/_data/'; + + let data = dataLoader.loadDataFromFile(data_dir + 'foo', fs); + test.equals(data.foo, 'bar'); + test.end(); +}); diff --git a/test/files/_data/data.json b/test/files/_data/data.json index d6d8ef572..1e3cc53b3 100644 --- a/test/files/_data/data.json +++ b/test/files/_data/data.json @@ -1,2 +1,2 @@ -{ "data" : "test" } +{ "data" : "test", "from_json" : "from_json" } diff --git a/test/files/_data/data.yaml b/test/files/_data/data.yaml new file mode 100644 index 000000000..50c5fd0cd --- /dev/null +++ b/test/files/_data/data.yaml @@ -0,0 +1 @@ +from_yaml: "from_yaml" diff --git a/test/files/_data/data.yml b/test/files/_data/data.yml new file mode 100644 index 000000000..e64d69624 --- /dev/null +++ b/test/files/_data/data.yml @@ -0,0 +1 @@ +from_yml: "from_yml" diff --git a/test/patternlab_tests.js b/test/patternlab_tests.js index 84eb81d2f..463d342ad 100644 --- a/test/patternlab_tests.js +++ b/test/patternlab_tests.js @@ -1,15 +1,27 @@ 'use strict'; -var tap = require('tap'); +const tap = require('tap'); tap.test('buildPatternData - should merge all JSON files in the data folder except listitems', function(test){ - var fs = require('fs-extra'); - var plMain = require('../core/lib/patternlab'); - var data_dir = './test/files/_data/'; + const fs = require('fs-extra'), + plMain = require('../core/lib/patternlab'), + data_dir = './test/files/_data/'; - var dataResult = plMain.build_pattern_data(data_dir, fs); + let dataResult = plMain.build_pattern_data(data_dir, fs); test.equals(dataResult.data, "test"); test.equals(dataResult.foo, "bar"); test.equals(dataResult.test_list_item, undefined); test.end(); }); + +tap.test('buildPatternData - can load json, yaml, and yml files', function(test) { + const fs = require('fs-extra'), + plMain = require('../core/lib/patternlab'), + data_dir = './test/files/_data/'; + + let dataResult = plMain.build_pattern_data(data_dir, fs); + test.equals(dataResult.from_yml, "from_yml"); + test.equals(dataResult.from_yaml, "from_yaml"); + test.equals(dataResult.from_json, "from_json"); + test.end(); +});