diff --git a/.babelrc b/.babelrc
index cf61652..c43265a 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,9 +1,31 @@
{
- "presets": [
- ["env", {
- "targets": {
- "node": "6.5",
- },
- }]
- ],
+ "env": {
+ "cli": {
+ "presets": [
+ ["env", {
+ "targets": {
+ "node": "6.5",
+ }
+ }]
+ ]
+ },
+ "test": {
+ "presets": [
+ ["env", {
+ "targets": {
+ "node": "6.5",
+ }
+ }]
+ ]
+ },
+ "browser": {
+ "presets": [
+ ["env", {
+ "targets": {
+ "browsers": "last 3 versions",
+ }
+ }]
+ ]
+ }
+ }
}
\ No newline at end of file
diff --git a/dist/cli/huron-cli.js b/dist/cli/huron-cli.js
index 8c612a8..96abbe5 100755
--- a/dist/cli/huron-cli.js
+++ b/dist/cli/huron-cli.js
@@ -93,6 +93,60 @@ module.exports = require("fs-extra");
"use strict";
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+/** @module cli/parse-arguments */
+/* eslint-disable space-unary-ops */
+
+// Requires
+/** @global */
+const program = __webpack_require__(18); // Easy program flags
+const path = __webpack_require__(0);
+
+exports.default = program;
+
+/**
+ * Process huron CLI arguments
+ *
+ * @function parseArgs
+ * @example node huron/dist/cli/huron-cli.js --config 'client/config/webpack.config.js' --production
+ */
+
+function parseArgs() {
+ const envArg = {};
+
+ process.argv = process.argv.filter(arg => {
+ if (-1 !== arg.indexOf('--env')) {
+ const envParts = arg.split('.')[1].split('=');
+
+ envArg[envParts[0]] = envParts[1] || true;
+ return false;
+ }
+
+ return true;
+ });
+
+ program.version('1.0.1').option('-c, --huron-config [huronConfig]', '[huronConfig] for all huron options', path.resolve(__dirname, '../default-config/huron.config.js')).option('-w, --webpack-config [webpackConfig]', '[webpackConfig] for all webpack options', path.resolve(__dirname, '../default-config/webpack.config.js')).option('-p, --production', 'compile assets once for production');
+
+ program.env = envArg;
+
+ // Only parse if we're not running tests
+ if (!process.env.npm_lifecycle_event || 'test' !== process.env.npm_lifecycle_event) {
+ program.parse(process.argv);
+ }
+}
+
+parseArgs();
+/* eslint-enable */
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -318,8 +372,8 @@ function removeFile(id, type, filepath, store) {
function writeSectionTemplate(filepath, store) {
const huron = store.get('config');
const sectionTemplate = wrapMarkup(fs.readFileSync(filepath, 'utf8'));
- const componentPath = './huron-sections/sections.hbs';
- const output = path.join(cwd, huron.get('root'), huron.get('output'), componentPath);
+ const componentPath = './huron-assets/section.hbs';
+ const output = path.join(cwd, huron.get('root'), componentPath);
// Move huron script and section template into huron root
fs.outputFileSync(output, sectionTemplate);
@@ -374,60 +428,6 @@ function matchKssDir(filepath, huron) {
return false;
}
-/***/ }),
-/* 4 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-/** @module cli/parse-arguments */
-/* eslint-disable space-unary-ops */
-
-// Requires
-/** @global */
-const program = __webpack_require__(18); // Easy program flags
-const path = __webpack_require__(0);
-
-exports.default = program;
-
-/**
- * Process huron CLI arguments
- *
- * @function parseArgs
- * @example node huron/dist/cli/huron-cli.js --config 'client/config/webpack.config.js' --production
- */
-
-function parseArgs() {
- const envArg = {};
-
- process.argv = process.argv.filter(arg => {
- if (-1 !== arg.indexOf('--env')) {
- const envParts = arg.split('.')[1].split('=');
-
- envArg[envParts[0]] = envParts[1] || true;
- return false;
- }
-
- return true;
- });
-
- program.version('1.0.1').option('-c, --huron-config [huronConfig]', '[huronConfig] for all huron options', path.resolve(__dirname, '../default-config/huron.config.js')).option('-w, --webpack-config [webpackConfig]', '[webpackConfig] for all webpack options', path.resolve(__dirname, '../default-config/webpack.config.js')).option('-p, --production', 'compile assets once for production');
-
- program.env = envArg;
-
- // Only parse if we're not running tests
- if (!process.env.npm_lifecycle_event || 'test' !== process.env.npm_lifecycle_event) {
- program.parse(process.argv);
- }
-}
-
-parseArgs();
-/* eslint-enable */
-
/***/ }),
/* 5 */
/***/ (function(module, exports) {
@@ -447,7 +447,7 @@ Object.defineProperty(exports, "__esModule", {
exports.updateTemplate = updateTemplate;
exports.deleteTemplate = deleteTemplate;
-var _utils = __webpack_require__(3);
+var _utils = __webpack_require__(4);
var utils = _interopRequireWildcard(_utils);
@@ -553,17 +553,21 @@ const requireTemplates = exports.requireTemplates = function requireTemplates(st
const requireRegex = new RegExp(`\\.html|\\.json|\\${huron.get('templates').extension}$`);
const requirePath = `'../${huron.get('output')}'`;
- // Initialize templates, js, css and HMR acceptance logic
+ // Initialize templates, js, css and Hot Module Replacement acceptance logic
const prepend = `
var store = require('./huron-store.js');
+var sectionTemplate = require('./section.hbs');
var assets = require.context(${requirePath}, true, ${requireRegex});
var modules = {};
+modules['${store.get('sectionTemplatePath')}'] = sectionTemplate;
+
assets.keys().forEach(function(key) {
modules[key] = assets(key);
});
if (module.hot) {
+ // Hot Module Replacement for huron components (json, hbs, html)
module.hot.accept(
assets.id,
() => {
@@ -589,6 +593,21 @@ if (module.hot) {
}
);
+ // Hot Module Replacement for sections template
+ module.hot.accept(
+ './section.hbs',
+ () => {
+ var newSectionTemplate = require('./section.hbs');
+ modules['${store.get('sectionTemplatePath')}'] = newSectionTemplate;
+ hotReplace(
+ './huron-assets/section.hbs',
+ newSectionTemplate,
+ modules
+ );
+ }
+ );
+
+ // Hot Module Replacement for data store
module.hot.accept(
'./huron-store.js',
() => {
@@ -648,7 +667,7 @@ var _actions = __webpack_require__(9);
var _requireTemplates = __webpack_require__(7);
-var _parseArgs = __webpack_require__(4);
+var _parseArgs = __webpack_require__(3);
var _parseArgs2 = _interopRequireDefault(_parseArgs);
@@ -800,7 +819,7 @@ var _handleTemplates = __webpack_require__(6);
var _handleKss = __webpack_require__(12);
-var _utils = __webpack_require__(3);
+var _utils = __webpack_require__(4);
var utils = _interopRequireWildcard(_utils);
@@ -866,7 +885,7 @@ function updateFile(filepath, store) {
let field;
let section;
- if (-1 !== filepath.indexOf(huron.get('sectionTemplate'))) {
+ if (filepath.includes(huron.get('sectionTemplate'))) {
return utils.writeSectionTemplate(filepath, store);
}
@@ -977,7 +996,7 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = generateConfig;
-var _parseArgs = __webpack_require__(4);
+var _parseArgs = __webpack_require__(3);
var _parseArgs2 = _interopRequireDefault(_parseArgs);
@@ -988,17 +1007,17 @@ var _requireExternal2 = _interopRequireDefault(_requireExternal);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/** @module cli/generate-config */
-
const cwd = process.cwd();
const path = __webpack_require__(0);
const url = __webpack_require__(23);
const fs = __webpack_require__(2);
const webpack = __webpack_require__(5);
const HTMLWebpackPlugin = __webpack_require__(20);
-const defaultConfig = __webpack_require__(17);
+const defaultWebpack = __webpack_require__(17);
const defaultHuron = __webpack_require__(16);
// Require configs passed in by user from CLI
+let defaultConfig = false;
const localConfigPath = !path.isAbsolute(_parseArgs2.default.webpackConfig) ? path.join(cwd, _parseArgs2.default.webpackConfig) : _parseArgs2.default.webpackConfig;
const localHuronPath = !path.isAbsolute(_parseArgs2.default.huronConfig) ? path.join(cwd, _parseArgs2.default.huronConfig) : _parseArgs2.default.huronConfig;
const localConfig = (0, _requireExternal2.default)(localConfigPath);
@@ -1025,16 +1044,15 @@ function generateConfig() {
newHuron = newHuron(_parseArgs2.default.env);
}
+ // Merge huron defaults with user settings
newHuron = Object.assign({}, defaultHuron, newHuron);
+ // Use user huron config to modify webpack defaults
+ defaultConfig = defaultWebpack(newHuron);
// Set ouput options
newConfig.output = Object.assign({}, defaultConfig.output, newConfig.output);
- newConfig.output.path = path.resolve(cwd, newHuron.root);
- if (!_parseArgs2.default.production) {
- newConfig.output.publicPath = `http://localhost:${newHuron.port}/${newHuron.root}`;
- } else {
- newConfig.output.publicPath = '';
- }
+ newConfig.output.path = defaultConfig.output.path;
+ newConfig.output.publicPath = defaultConfig.output.publicPath;
// configure entries
newConfig = configureEntries(newHuron, newConfig);
@@ -1112,14 +1130,15 @@ function configureLoaders(huron, config) {
const templatesLoader = huron.templates.rule || {};
const newConfig = config;
- templatesLoader.include = [path.join(cwd, huron.root)];
+ // Make sure we're only using templates loader for files in huron root
+ templatesLoader.include = [path.join(cwd, huron.root, huron.output)];
+
+ // Normalize module and module.rules
newConfig.module = newConfig.module || {};
newConfig.module.rules = newConfig.module.rules || newConfig.module.loaders || [];
- newConfig.module.rules.push({
- test: /\.html$/,
- use: 'html-loader',
- include: [path.join(cwd, huron.root)]
- }, templatesLoader);
+
+ // Add default loaders
+ newConfig.module.rules = defaultConfig.module.rules.concat(newConfig.module.rules, templatesLoader);
return newConfig;
}
@@ -1132,22 +1151,22 @@ function configureLoaders(huron, config) {
* @return {object} newConfig - updated data store
*/
function configurePrototypes(huron, config) {
- const wrapperTemplate = fs.readFileSync(path.join(__dirname, '../../templates/prototype-template.ejs'), 'utf8');
+ const wrapperTemplate = fs.readFileSync(path.join(__dirname, '../../templates/prototype-template.hbs'), 'utf8');
const defaultHTMLPluginOptions = {
- title: '',
+ title: 'Huron',
window: huron.window,
js: [],
css: [],
filename: 'index.html',
- template: path.join(cwd, huron.root, 'huron-assets/prototype-template.ejs'),
+ template: path.join(cwd, huron.root, 'huron-assets/prototype-template.hbs'),
inject: false,
chunks: [huron.entry]
};
const newConfig = config;
// Write prototype template file for HTML webpack plugin
- fs.outputFileSync(path.join(cwd, huron.root, 'huron-assets/prototype-template.ejs'), wrapperTemplate);
+ fs.outputFileSync(path.join(cwd, huron.root, 'huron-assets/prototype-template.hbs'), wrapperTemplate);
huron.prototypes.forEach(prototype => {
const newPrototype = prototype;
@@ -1255,7 +1274,7 @@ exports.deleteHTML = deleteHTML;
exports.updatePrototype = updatePrototype;
exports.deletePrototype = deletePrototype;
-var _utils = __webpack_require__(3);
+var _utils = __webpack_require__(4);
var utils = _interopRequireWildcard(_utils);
@@ -1362,7 +1381,7 @@ Object.defineProperty(exports, "__esModule", {
exports.updateKSS = updateKSS;
exports.deleteKSS = deleteKSS;
-var _utils = __webpack_require__(3);
+var _utils = __webpack_require__(4);
var utils = _interopRequireWildcard(_utils);
@@ -1751,7 +1770,7 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = startWebpack;
-var _parseArgs = __webpack_require__(4);
+var _parseArgs = __webpack_require__(3);
var _parseArgs2 = _interopRequireDefault(_parseArgs);
@@ -1868,35 +1887,50 @@ module.exports = {
"use strict";
+var _parseArgs = __webpack_require__(3);
+
+var _parseArgs2 = _interopRequireDefault(_parseArgs);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
const webpack = __webpack_require__(5);
const path = __webpack_require__(0);
-module.exports = {
- entry: {},
- output: {
- // path: [huron root directory],
- filename: '[name].js',
- chunkFilename: '[name].chunk.min.js'
- },
- plugins: [new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin()],
- resolve: {
- modulesDirectories: [path.resolve(__dirname, '../src/js')]
- },
- resolveLoader: {
- modulesDirectories: ['web_loaders', 'web_modules', 'node_loaders', 'node_modules', path.resolve(__dirname, '../node_modules')]
- },
- module: {
- rules: [{
- test: /\.html?$/,
- use: [{
- loader: 'dom-loader',
- options: {
- tag: 'dom-module'
+module.exports = huron => {
+ const cwd = process.cwd();
+
+ return {
+ entry: {},
+ output: {
+ path: path.join(cwd, huron.root),
+ publicPath: _parseArgs2.default.production ? '' : `http://localhost:${huron.port}/${huron.root}`,
+ filename: '[name].js',
+ chunkFilename: '[name].chunk.min.js'
+ },
+ plugins: [new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin()],
+ resolve: {
+ modulesDirectories: [path.resolve(__dirname, '../src/js')]
+ },
+ resolveLoader: {
+ modulesDirectories: ['web_loaders', 'web_modules', 'node_loaders', 'node_modules', path.resolve(__dirname, '../node_modules')]
+ },
+ module: {
+ rules: [{
+ test: /\.html$/,
+ include: [path.join(cwd, huron.root, huron.output)],
+ use: 'html-loader'
+ }, {
+ test: /\.(hbs|handlebars)$/,
+ include: [path.join(cwd, huron.root, 'huron-assets')],
+ use: {
+ loader: 'handlebars-loader',
+ options: {
+ helperDirs: path.join(__dirname, '../../', 'templates/handlebars-helpers')
+ }
}
- }, 'html-loader']
- // include: ['path/to/templates']
- }]
- }
+ }]
+ }
+ };
};
/***/ }),
diff --git a/dist/cli/huron-cli.js.map b/dist/cli/huron-cli.js.map
index 43590ef..30597f2 100644
--- a/dist/cli/huron-cli.js.map
+++ b/dist/cli/huron-cli.js.map
@@ -1 +1 @@
-{"version":3,"file":"huron-cli.js","sources":["webpack:///webpack/bootstrap c39ca41aeebe852abcea","webpack:///external \"path\"","webpack:///external \"chalk\"","webpack:///external \"fs-extra\"","webpack:///src/cli/utils.js","webpack:///src/cli/parse-args.js","webpack:///external \"webpack\"","webpack:///src/cli/handle-templates.js","webpack:///src/cli/require-templates.js","webpack:///src/cli/huron-cli.js","webpack:///src/cli/actions.js","webpack:///src/cli/generate-config.js","webpack:///src/cli/handle-html.js","webpack:///src/cli/handle-kss.js","webpack:///src/cli/huron-store.js","webpack:///src/cli/require-external.js","webpack:///src/cli/server.js","webpack:///src/default-config/huron.config.js","webpack:///src/default-config/webpack.config.js","webpack:///external \"commander\"","webpack:///external \"gaze\"","webpack:///external \"html-webpack-plugin\"","webpack:///external \"immutable\"","webpack:///external \"kss\"","webpack:///external \"url\"","webpack:///external \"webpack-dev-server\""],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"../\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 25);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c39ca41aeebe852abcea","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 0\n// module chunks = 0","module.exports = require(\"chalk\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"chalk\"\n// module id = 1\n// module chunks = 0","module.exports = require(\"fs-extra\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"fs-extra\"\n// module id = 2\n// module chunks = 0","/** @module cli/utilities */\n\nconst cwd = process.cwd(); // Current working directory\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Ensure predictable data structure for KSS section data\n *\n * @function normalizeSectionData\n * @param {object} section - section data\n * @return {object} section data\n */\nexport function normalizeSectionData(section) {\n const data = section.data || section;\n\n if (! data.referenceURI || '' === data.referenceURI) {\n data.referenceURI = section.referenceURI();\n }\n\n return data;\n}\n\n/**\n * Ensure predictable data structure for KSS section data\n *\n * @function writeSectionData\n * @param {object} store - data store\n * @param {object} section - section data\n * @param {string} sectionPath - output destination for section data file\n */\nexport function writeSectionData(store, section, sectionPath = false) {\n let outputPath = sectionPath;\n let sectionFileInfo;\n\n if (! outputPath && {}.hasOwnProperty.call(section, 'kssPath')) {\n sectionFileInfo = path.parse(section.kssPath);\n outputPath = path.join(\n sectionFileInfo.dir,\n `${sectionFileInfo.name}.json`\n );\n }\n\n // Output section data\n if (outputPath) {\n return writeFile(\n section.referenceURI,\n 'section',\n outputPath,\n JSON.stringify(section),\n store\n );\n }\n\n console.warn( // eslint-disable-line no-console\n chalk.red(`Failed to write section data for ${section.referenceURI}`)\n );\n return false;\n}\n\n/**\n * Find .json from a template file or vice versa\n *\n * @function getTemplateDataPair\n * @param {object} file - file object from path.parse()\n * @param {object} section - KSS section data\n * @return {string} relative path to module JSON file\n */\nexport function getTemplateDataPair(file, section, store) {\n const huron = store.get('config');\n const kssDir = matchKssDir(file.dir, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const partnerType = '.json' === file.ext ? 'template' : 'data';\n const partnerExt = '.json' === file.ext ?\n huron.get('templates').extension :\n '.json';\n\n const pairPath = path.join(\n componentPath,\n generateFilename(\n section.referenceURI,\n partnerType,\n partnerExt,\n store\n )\n );\n\n return `./${pairPath}`;\n }\n\n return false;\n}\n\n/**\n * Normalize a section title for use as a filename\n *\n * @function normalizeHeader\n * @param {string} header - section header extracted from KSS documentation\n * @return {string} modified header, lowercase and words separated by dash\n */\nexport function normalizeHeader(header) {\n return header\n .toLowerCase()\n .replace(/\\s?\\W\\s?/g, '-');\n}\n\n/**\n * Wrap html in required template tags\n *\n * @function wrapMarkup\n * @param {string} content - html or template markup\n * @param {string} templateId - id of template (should be section reference)\n * @return {string} modified HTML\n */\nexport function wrapMarkup(content, templateId) {\n return `\n\n${content}\n\n\\n`;\n}\n\n/**\n * Generate a filename based on referenceURI, type and file object\n *\n * @function generateFilename\n * @param {string} id - The name of the file (with extension).\n * @param {string} type - the type of file output\n * @param {object} ext - file extension\n * @param {store} store - data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function generateFilename(id, type, ext, store) {\n // Type of file and its corresponding extension(s)\n const types = store.get('types');\n const outputExt = '.scss' !== ext ? ext : '.html';\n\n /* eslint-disable */\n if (-1 === types.indexOf(type)) {\n console.log(`Huron data ${type} does not exist`);\n return false;\n }\n /* eslint-enable */\n\n return `${id}-${type}${outputExt}`;\n}\n\n/**\n * Copy an HTML file into the huron output directory.\n *\n * @function writeFile\n * @param {string} id - The name of the file (with extension).\n * @param {string} content - The content of the file to write.\n * @param {string} type - the type of file output\n * @param {object} store - The data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function writeFile(id, type, filepath, content, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n const filename = generateFilename(id, type, file.ext, store);\n const kssDir = matchKssDir(filepath, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const outputRelative = path.join(\n huron.get('output'),\n componentPath,\n `${filename}`\n );\n const outputPath = path.resolve(cwd, huron.get('root'), outputRelative);\n let newContent = content;\n\n if ('data' !== type && 'section' !== type) {\n newContent = wrapMarkup(content, id);\n }\n\n try {\n fs.outputFileSync(outputPath, newContent);\n console.log(chalk.green(`Writing ${outputRelative}`)); // eslint-disable-line no-console\n } catch (e) {\n console.log(chalk.red(`Failed to write ${outputRelative}`)); // eslint-disable-line no-console\n }\n\n return `./${outputRelative.replace(`${huron.get('output')}/`, '')}`;\n }\n\n return false;\n}\n\n/**\n * Delete a file in the huron output directory\n *\n * @function removeFile\n * @param {string} filename - The name of the file (with extension).\n * @param {object} store - The data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function removeFile(id, type, filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n const filename = generateFilename(id, type, file.ext, store);\n const kssDir = matchKssDir(filepath, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const outputRelative = path.join(\n huron.get('output'),\n componentPath,\n `${filename}`\n );\n const outputPath = path.resolve(cwd, huron.get('root'), outputRelative);\n\n try {\n fs.removeSync(outputPath);\n console.log(chalk.green(`Removing ${outputRelative}`)); // eslint-disable-line no-console\n } catch (e) {\n console.log( // eslint-disable-line no-console\n chalk.red(`${outputRelative} does not exist or cannot be deleted`)\n );\n }\n\n return `./${outputRelative.replace(`${huron.get('output')}/`, '')}`;\n }\n\n return false;\n}\n\n/**\n * Write a template for sections\n *\n * @function writeSectionTemplate\n * @param {string} filepath - the original template file\n * @param {object} store - data store\n * @return {object} updated store\n */\nexport function writeSectionTemplate(filepath, store) {\n const huron = store.get('config');\n const sectionTemplate = wrapMarkup(fs.readFileSync(filepath, 'utf8'));\n const componentPath = './huron-sections/sections.hbs';\n const output = path.join(\n cwd,\n huron.get('root'),\n huron.get('output'),\n componentPath\n );\n\n // Move huron script and section template into huron root\n fs.outputFileSync(output, sectionTemplate);\n console.log(chalk.green(`writing section template to ${output}`)); // eslint-disable-line no-console\n\n return store.set('sectionTemplatePath', componentPath);\n}\n\n/**\n * Request for section data based on section reference\n *\n * @function writeSectionTemplate\n * @param {string} search - key on which to match section\n * @param {field} string - field in which to look to determine section\n * @param {obj} store - sections memory store\n */\nexport function getSection(search, field, store) {\n const sectionValues = store\n .getIn(['sections', 'sectionsByPath'])\n .valueSeq();\n let selectedSection = false;\n\n if (field) {\n selectedSection = sectionValues\n .filter((value) => value[field] === search)\n .get(0);\n } else {\n selectedSection = store.getIn(['sections', 'sectionsByPath', search]);\n }\n\n return selectedSection;\n}\n\n/**\n * Find which configured KSS directory a filepath exists in\n *\n * @function matchKssDir\n * @param {string} filepath - filepath to search for\n * @param {object} huron - huron configuration\n * @return {string} kssMatch - relative path to KSS directory\n */\nexport function matchKssDir(filepath, huron) {\n const kssSource = huron.get('kss');\n /* eslint-disable space-unary-ops */\n // Include forward slash in our test to make sure we're matchin a directory, not a file extension\n const kssMatch = kssSource.filter((dir) => filepath.includes(`/${dir}`));\n /* eslint-enable space-unary-ops */\n\n if (kssMatch.length) {\n return kssMatch[0];\n }\n\n console.error(\n chalk.red(`filepath ${filepath} does not exist in any\n of the configured KSS directories`)\n );\n\n return false;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/utils.js","/** @module cli/parse-arguments */\n/* eslint-disable space-unary-ops */\n\n// Requires\n/** @global */\nconst program = require('commander'); // Easy program flags\nconst path = require('path');\n\nexport default program;\n\n/**\n * Process huron CLI arguments\n *\n * @function parseArgs\n * @example node huron/dist/cli/huron-cli.js --config 'client/config/webpack.config.js' --production\n */\nfunction parseArgs() {\n const envArg = {};\n\n process.argv = process.argv.filter((arg) => {\n if (-1 !== arg.indexOf('--env')) {\n const envParts = arg\n .split('.')[1]\n .split('=');\n\n envArg[envParts[0]] = envParts[1] || true;\n return false;\n }\n\n return true;\n });\n\n program.version('1.0.1')\n .option(\n '-c, --huron-config [huronConfig]',\n '[huronConfig] for all huron options',\n path.resolve(__dirname, '../default-config/huron.config.js')\n )\n .option(\n '-w, --webpack-config [webpackConfig]',\n '[webpackConfig] for all webpack options',\n path.resolve(__dirname, '../default-config/webpack.config.js')\n )\n .option('-p, --production', 'compile assets once for production');\n\n program.env = envArg;\n\n // Only parse if we're not running tests\n if (\n ! process.env.npm_lifecycle_event ||\n 'test' !== process.env.npm_lifecycle_event\n ) {\n program.parse(process.argv);\n }\n}\n\nparseArgs();\n/* eslint-enable */\n\n\n\n// WEBPACK FOOTER //\n// src/cli/parse-args.js","module.exports = require(\"webpack\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack\"\n// module id = 5\n// module chunks = 0","/** @module cli/template-handler */\nimport * as utils from './utils';\n\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk');\n\n/**\n * Handle update of a template or data (json) file\n *\n * @function updateTemplate\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated memory store\n */\nexport function updateTemplate(filepath, section, store) {\n const file = path.parse(filepath);\n const pairPath = utils.getTemplateDataPair(file, section, store);\n const type = '.json' === file.ext ? 'data' : 'template';\n const newSection = section;\n const newStore = store;\n let content = false;\n\n try {\n content = fs.readFileSync(filepath, 'utf8');\n } catch (e) {\n console.log(chalk.red(`${filepath} does not exist`));\n }\n\n if (content) {\n const requirePath = utils.writeFile(\n newSection.referenceURI,\n type,\n filepath,\n content,\n newStore\n );\n newSection[`${type}Path`] = requirePath;\n\n if ('template' === type) {\n newSection.templateContent = content;\n\n // Rewrite section data with template content\n newSection.sectionPath = utils.writeSectionData(newStore, newSection);\n }\n\n return newStore\n .setIn(\n ['templates', requirePath],\n pairPath\n )\n .setIn(\n ['sections', 'sectionsByPath', newSection.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle removal of a template or data (json) file\n *\n * @function deleteTemplate\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated memory store\n */\nexport function deleteTemplate(filepath, section, store) {\n const file = path.parse(filepath);\n const type = '.json' === file.ext ? 'data' : 'template';\n const newSection = section;\n const newStore = store;\n\n // Remove partner\n const requirePath = utils.removeFile(\n newSection.referenceURI,\n type,\n filepath,\n newStore\n );\n delete newSection[`${type}Path`];\n\n return newStore\n .deleteIn(['templates', requirePath])\n .setIn(\n ['sections', 'sectionsByPath', newSection.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-templates.js","/** @module cli/require-templates */\n\nconst path = require('path');\nconst fs = require('fs-extra');\n\nconst cwd = process.cwd();\nconst huronScript = fs.readFileSync(\n path.join(__dirname, '../web/huron.js'),\n 'utf8'\n);\n\n/**\n * Write code for requiring all generated huron assets\n * Note: prepended and appended code in this file should roughly follow es5 syntax for now,\n * as it will not pass through the Huron internal babel build nor can we assume the user is\n * working with babel.\n *\n * @function requireTemplates\n * @param {object} store - memory store\n */\nexport const requireTemplates = function requireTemplates(store) {\n const huron = store.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n const requireRegex = new RegExp(`\\\\.html|\\\\.json|\\\\${\n huron.get('templates').extension\n }$`);\n const requirePath = `'../${huron.get('output')}'`;\n\n // Initialize templates, js, css and HMR acceptance logic\n const prepend = `\nvar store = require('./huron-store.js');\nvar assets = require.context(${requirePath}, true, ${requireRegex});\nvar modules = {};\n\nassets.keys().forEach(function(key) {\n modules[key] = assets(key);\n});\n\nif (module.hot) {\n module.hot.accept(\n assets.id,\n () => {\n var newAssets = require.context(\n ${requirePath},\n true,\n ${requireRegex}\n );\n var newModules = newAssets.keys()\n .map((key) => {\n return [key, newAssets(key)];\n })\n .filter((newModule) => {\n return modules[newModule[0]] !== newModule[1];\n });\n\n updateStore(require('./huron-store.js'));\n\n newModules.forEach((module) => {\n modules[module[0]] = module[1];\n hotReplace(module[0], module[1], modules);\n });\n }\n );\n\n module.hot.accept(\n './huron-store.js',\n () => {\n updateStore(require('./huron-store.js'));\n }\n );\n}\\n`;\n\n const append = `\nfunction hotReplace(key, module, modules) {\n insert.modules = modules;\n if (key === store.sectionTemplatePath) {\n insert.cycleSections();\n } else {\n insert.inserted = [];\n insert.loadModule(key, module, false);\n }\n};\n\nfunction updateStore(newStore) {\n insert.store = newStore;\n}\\n`;\n\n // Write the contents of this script.\n // @todo lint this file.\n fs.outputFileSync(\n path.join(outputPath, 'huron.js'),\n `/*eslint-disable*/\\n\n${prepend}\\n\\n${huronScript}\\n\\n${append}\\n\n/*eslint-enable*/\\n`\n );\n};\n\n/**\n * Output entire data store to a JS object and handle if any KSS data has changed\n *\n * @function writeStore\n * @param {object} store - memory store\n * @param {string} changed - filepath of changed KSS section, if applicable\n */\nexport const writeStore = function writeStore(store) {\n const huron = store.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n\n // Write updated data store\n // @todo lint this file.\n fs.outputFileSync(\n path.join(outputPath, 'huron-store.js'),\n `/*eslint-disable*/\n module.exports = ${JSON.stringify(store.toJSON())}\n /*eslint-disable*/\\n`\n );\n};\n\n\n\n\n// WEBPACK FOOTER //\n// src/cli/require-templates.js","// Local imports\nimport { initFiles, updateFile, deleteFile } from './actions';\nimport { requireTemplates, writeStore } from './require-templates';\nimport program from './parse-args';\nimport startWebpack from './server';\nimport { dataStructure, config } from './huron-store';\n\n// Modules\nconst path = require('path');\nconst Gaze = require('gaze').Gaze;\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Huron configuration object\n *\n * @global\n */\nconst huron = dataStructure.get('config');\n\n/**\n * Available file extensions. Extensions should not include the leading '.'\n *\n * @global\n */\nconst extensions = [\n huron.get('kssExtension'),\n huron.get('templates').extension,\n 'html',\n 'json',\n].map((extension) => extension.replace('.', ''));\n\n// Generate watch list for Gaze, start gaze\nconst gazeWatch = [];\n\n// Push KSS source directories and section template to Gaze\ngazeWatch.push(path.resolve(__dirname, huron.get('sectionTemplate')));\nhuron.get('kss').forEach((sourceDir) => {\n let gazeDir = sourceDir;\n\n /* eslint-disable space-unary-ops */\n if ('/' === sourceDir.slice(-1)) {\n gazeDir = sourceDir.slice(0, -1);\n }\n /* eslint-enable space-unary-ops */\n\n gazeWatch.push(\n `${gazeDir}/**/*.+(${extensions.join('|')})`\n );\n});\n\n/**\n * Gaze instance for watching all files, including KSS, html, hbs/template, and JSON\n *\n * @global\n */\nconst gaze = new Gaze(gazeWatch);\n\n/**\n * Initialize data store with files from gaze and original data structure\n *\n * @global\n */\nconst store = initFiles(gaze.watched(), dataStructure);\n\nrequireTemplates(store);\nwriteStore(store);\n\nif (! program.production) {\n /** @module cli/gaze */\n let newStore = store;\n\n /**\n * Anonymous handler for Gaze 'changed' event indicating a file has changed\n *\n * @callback changed\n * @listens gaze:changed\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('changed', (filepath) => {\n newStore = updateFile(filepath, newStore);\n console.log(chalk.green(`${filepath} updated!`));\n });\n\n /**\n * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories\n *\n * @callback added\n * @listens gaze:added\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('added', (filepath) => {\n newStore = updateFile(filepath, newStore);\n writeStore(newStore);\n console.log(chalk.blue(`${filepath} added!`));\n });\n\n /**\n * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed\n *\n * @callback renamed\n * @listens gaze:renamed\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('renamed', (newPath, oldPath) => {\n newStore = deleteFile(oldPath, newStore);\n newStore = updateFile(newPath, newStore);\n writeStore(newStore);\n console.log(chalk.blue(`${newPath} added!`));\n });\n\n /**\n * Anonymous handler for Gaze 'deleted' event indicating a file has been removed\n *\n * @callback deleted\n * @listens gaze:deleted\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('deleted', (filepath) => {\n newStore = deleteFile(filepath, newStore);\n writeStore(newStore);\n console.log(chalk.red(`${filepath} deleted`));\n });\n} else {\n gaze.close();\n}\n\n// Start webpack or build for production\nstartWebpack(config);\n\nif (module.hot) {\n module.hot.accept();\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/huron-cli.js","/** @module cli/actions */\n\n// Imports\nimport {\n updateHTML,\n deleteHTML,\n updatePrototype,\n deletePrototype,\n} from './handle-html';\nimport { updateTemplate, deleteTemplate } from './handle-templates';\nimport { updateKSS, deleteKSS } from './handle-kss';\nimport * as utils from './utils';\n\n// Requires\nconst path = require('path');\nconst chalk = require('chalk'); // Colorize terminal output\n\n// EXPORTED FUNCTIONS\n\n/**\n * Recursively loop through initial watched files list from Gaze.\n *\n * @param {object} data - object containing directory and file paths\n * @param {object} store - memory store\n * @param {object} huron - huron configuration options\n * @return {object} newStore - map object of entire data store\n */\nexport function initFiles(data, store, depth = 0) {\n const type = Object.prototype.toString.call(data);\n let newStore = store;\n let info;\n let files;\n\n switch (type) {\n case '[object Object]':\n files = Object.keys(data);\n newStore = files.reduce(\n (prevStore, file) => initFiles(data[file], prevStore, depth),\n newStore\n );\n break;\n\n case '[object Array]':\n newStore = data.reduce(\n (prevStore, file) => initFiles(file, prevStore, depth),\n newStore\n );\n break;\n\n case '[object String]':\n info = path.parse(data);\n if (info.ext) {\n newStore = updateFile(data, store);\n }\n break;\n\n default:\n break;\n }\n\n return newStore;\n}\n\n/**\n * Logic for updating and writing file information based on file type (extension)\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n * @return {object} store - map object of map object of entire data store\n */\nexport function updateFile(filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n let field;\n let section;\n\n if (- 1 !== filepath.indexOf(huron.get('sectionTemplate'))) {\n return utils.writeSectionTemplate(filepath, store);\n }\n\n switch (file.ext) {\n // Plain HTML template, external\n case '.html':\n section = utils.getSection(file.base, 'markup', store);\n\n if (section) {\n return updateHTML(filepath, section, store);\n } else if (\n - 1 !== file.dir.indexOf('prototypes') &&\n - 1 !== file.name.indexOf('prototype-')\n ) {\n return updatePrototype(filepath, store);\n }\n\n console.log(chalk.red(`Failed to write file: ${file.name}`));\n break;\n\n // Handlebars template, external\n case huron.get('templates').extension:\n case '.json':\n field = ('.json' === file.ext) ? 'data' : 'markup';\n section = utils.getSection(file.base, field, store);\n\n if (section) {\n return updateTemplate(filepath, section, store);\n }\n\n console.log( // eslint-disable-line no-console\n chalk.red(`Could not find associated KSS section for ${filepath}`)\n );\n break;\n\n // KSS documentation (default extension is `.css`)\n // Will also output a template if markup is inline\n // Note: inline markup does _not_ support handlebars currently\n case huron.get('kssExtension'):\n return updateKSS(filepath, store);\n\n // This should never happen if Gaze is working properly\n default:\n return store;\n }\n\n return store;\n}\n\n/**\n * Logic for deleting file information and files based on file type (extension)\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n * @return {object} newStore - map object of map object of entire data store\n */\nexport function deleteFile(filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n let field = '';\n let section = null;\n let newStore = store;\n\n switch (file.ext) {\n // Plain HTML template, external\n case '.html':\n section = utils.getSection(file.base, 'markup', store);\n\n if (section) {\n newStore = deleteHTML(filepath, section, store);\n } else if (\n - 1 !== file.dir.indexOf('prototypes') &&\n - 1 !== file.name.indexOf('prototype-')\n ) {\n newStore = deletePrototype(filepath, store);\n }\n break;\n\n case huron.get('templates').extension:\n case '.json':\n field = ('.json' === file.ext) ? 'data' : 'markup';\n section = utils.getSection(file.base, field, store);\n\n if (section) {\n newStore = deleteTemplate(filepath, section, store);\n }\n break;\n\n case huron.get('kssExtension'):\n section = utils.getSection(filepath, false, store);\n\n if (section) {\n newStore = deleteKSS(filepath, section, store);\n }\n break;\n\n default:\n console.warn( // eslint-disable-line no-console\n chalk.red(`Could not delete: ${file.name}`)\n );\n break;\n }\n\n return newStore;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/actions.js","/** @module cli/generate-config */\n\nimport program from './parse-args';\nimport requireExternal from './require-external';\n\nconst cwd = process.cwd();\nconst path = require('path');\nconst url = require('url');\nconst fs = require('fs-extra');\nconst webpack = require('webpack');\nconst HTMLWebpackPlugin = require('html-webpack-plugin');\nconst defaultConfig = require('../default-config/webpack.config');\nconst defaultHuron = require('../default-config/huron.config');\n\n// Require configs passed in by user from CLI\nconst localConfigPath = ! path.isAbsolute(program.webpackConfig) ?\n path.join(cwd, program.webpackConfig) :\n program.webpackConfig;\nconst localHuronPath = ! path.isAbsolute(program.huronConfig) ?\n path.join(cwd, program.huronConfig) :\n program.huronConfig;\nconst localConfig = requireExternal(localConfigPath);\nconst localHuron = requireExternal(localHuronPath);\n\n/**\n * Generate a mutant hybrid of the huron default webpack config and your local webpack config\n *\n * @function generateConfig\n * @param {object} config - local webpack config\n * @return {object} newConfig - updated data store\n */\nexport default function generateConfig() {\n let newConfig = localConfig;\n let newHuron = localHuron;\n\n // Execute config function, if provided\n if ('function' === typeof newConfig) {\n newConfig = newConfig(program.env);\n }\n\n // Execute huron config function, if provided\n if ('function' === typeof newHuron) {\n newHuron = newHuron(program.env);\n }\n\n newHuron = Object.assign({}, defaultHuron, newHuron);\n\n // Set ouput options\n newConfig.output = Object.assign({}, defaultConfig.output, newConfig.output);\n newConfig.output.path = path.resolve(cwd, newHuron.root);\n if (! program.production) {\n newConfig.output.publicPath = `http://localhost:${newHuron.port}/${newHuron.root}`;\n } else {\n newConfig.output.publicPath = '';\n }\n\n // configure entries\n newConfig = configureEntries(newHuron, newConfig);\n\n // configure plugins\n newConfig = configurePlugins(newHuron, newConfig);\n\n // configure loaders\n newConfig = configureLoaders(newHuron, newConfig);\n\n // Add HTMLWebpackPlugin for each configured prototype\n newConfig = configurePrototypes(newHuron, newConfig);\n\n // Remove existing devServer settings\n delete newConfig.devServer;\n\n return {\n huron: newHuron,\n webpack: newConfig,\n };\n}\n\n/**\n * Configure and manage webpack entry points\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configureEntries(huron, config) {\n const entry = config.entry[huron.entry];\n const newConfig = config;\n\n newConfig.entry = {};\n if (! program.production) {\n newConfig.entry[huron.entry] = [\n `webpack-dev-server/client?http://localhost:${huron.port}`,\n 'webpack/hot/dev-server',\n path.join(cwd, huron.root, 'huron-assets/huron'),\n ].concat(entry);\n } else {\n newConfig.entry[huron.entry] = [\n path.join(cwd, huron.root, 'huron-assets/huron'),\n ].concat(entry);\n }\n\n return newConfig;\n}\n\n/**\n * Configure and manage webpack plugins\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configurePlugins(huron, config) {\n const newConfig = config;\n\n newConfig.plugins = config.plugins || [];\n\n if (! program.production) {\n if (newConfig.plugins && newConfig.plugins.length) {\n newConfig.plugins = newConfig.plugins.filter(\n (plugin) => 'HotModuleReplacementPlugin' !== plugin.constructor.name &&\n 'NamedModulesPlugin' !== plugin.constructor.name\n );\n }\n newConfig.plugins = newConfig.plugins\n .concat([\n new webpack.HotModuleReplacementPlugin(),\n new webpack.NamedModulesPlugin(),\n ]);\n }\n\n return newConfig;\n}\n\n/**\n * Configure and manage webpack loaders\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configureLoaders(huron, config) {\n // Manage loaders\n const templatesLoader = huron.templates.rule || {};\n const newConfig = config;\n\n templatesLoader.include = [path.join(cwd, huron.root)];\n newConfig.module = newConfig.module || {};\n newConfig.module.rules = newConfig.module.rules ||\n newConfig.module.loaders ||\n [];\n newConfig.module.rules.push(\n {\n test: /\\.html$/,\n use: 'html-loader',\n include: [path.join(cwd, huron.root)],\n },\n templatesLoader\n );\n\n return newConfig;\n}\n\n/**\n * Create an HTML webpack plugin for each configured prototype\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configurePrototypes(huron, config) {\n const wrapperTemplate = fs.readFileSync(\n path.join(__dirname, '../../templates/prototype-template.ejs'),\n 'utf8'\n );\n\n const defaultHTMLPluginOptions = {\n title: '',\n window: huron.window,\n js: [],\n css: [],\n filename: 'index.html',\n template: path.join(\n cwd,\n huron.root,\n 'huron-assets/prototype-template.ejs'\n ),\n inject: false,\n chunks: [huron.entry],\n };\n const newConfig = config;\n\n // Write prototype template file for HTML webpack plugin\n fs.outputFileSync(\n path.join(cwd, huron.root, 'huron-assets/prototype-template.ejs'),\n wrapperTemplate\n );\n\n huron.prototypes.forEach((prototype) => {\n const newPrototype = prototype;\n let opts = {};\n\n // Merge configured settings with default settings\n if ('string' === typeof prototype) {\n opts = Object.assign({}, defaultHTMLPluginOptions, {\n title: prototype,\n filename: `${prototype}.html`,\n });\n } else if (\n 'object' === typeof prototype &&\n {}.hasOwnProperty.call(prototype, 'title')\n ) {\n // Create filename based on configured title if not provided\n if (! prototype.filename) {\n newPrototype.filename = `${prototype.title}.html`;\n }\n\n // Move css assets for this prototype,\n // reset css option with new file paths\n if (prototype.css) {\n newPrototype.css = moveAdditionalAssets(prototype.css, 'css', huron);\n }\n\n // Move js assets for this prototype,\n // reset js option with new file paths\n if (prototype.js) {\n newPrototype.js = moveAdditionalAssets(prototype.js, 'js', huron);\n }\n\n opts = Object.assign({}, defaultHTMLPluginOptions, newPrototype);\n }\n\n // Move global css assets,\n // reset css option with new file paths\n if (huron.css.length) {\n opts.css = opts.css.concat(\n moveAdditionalAssets(huron.css, 'css', huron)\n );\n }\n\n // Move global js assets,\n // reset js option with new file paths\n if (huron.js.length) {\n opts.js = opts.js.concat(\n moveAdditionalAssets(huron.js, 'js', huron)\n );\n }\n\n // Push a new plugin for each configured prototype\n if (Object.keys(opts).length) {\n newConfig.plugins.push(\n new HTMLWebpackPlugin(opts)\n );\n }\n });\n\n return newConfig;\n}\n\n/**\n * Move relative (and local) js and css assets provided in huron options\n *\n * @param {array|string} assets - array of assets or single asset\n * @param {string} subdir - subdirectory in huron root from which to load additional asset\n * @param {object} huron - huron configuration object\n * @return {array} assetResults - paths to js and css assets\n */\nfunction moveAdditionalAssets(assets, subdir = '', huron) {\n const currentAssets = [].concat(assets);\n const assetResults = [];\n\n currentAssets.forEach((asset) => {\n const assetInfo = path.parse(asset);\n const assetURL = url.parse(asset);\n const sourcePath = path.join(cwd, asset);\n const outputPath = path.resolve(cwd, huron.root, subdir, assetInfo.base);\n const loadPath = program.production ?\n path.join(subdir, assetInfo.base) :\n path.join('/', subdir, assetInfo.base); // Use absolute path in development\n let contents = false;\n\n if (\n ! path.isAbsolute(asset) &&\n ! assetURL.protocol\n ) {\n try {\n contents = fs.readFileSync(sourcePath);\n } catch (e) {\n console.warn(`could not read ${sourcePath}`);\n }\n\n if (contents) {\n fs.outputFileSync(outputPath, contents);\n assetResults.push(loadPath);\n }\n } else {\n assetResults.push(asset);\n }\n });\n\n return assetResults;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/generate-config.js","/** @module cli/html-handler */\nimport * as utils from './utils';\n\nconst path = require('path');\nconst fs = require('fs-extra');\n\n/**\n * Handle update of an HMTL template\n *\n * @function updateHTML\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updateHTML(filepath, section, store) {\n const file = path.parse(filepath);\n const content = fs.readFileSync(filepath, 'utf8');\n const newSection = section;\n\n if (content) {\n newSection.templatePath = utils.writeFile(\n section.referenceURI,\n 'template',\n filepath,\n content,\n store\n );\n newSection.templateContent = content;\n\n // Rewrite section data with template content\n newSection.sectionPath = utils.writeSectionData(store, newSection);\n\n return store\n .setIn(\n ['sections', 'sectionsByPath', section.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n console.log(`File ${file.base} could not be read`);\n return store;\n}\n\n/**\n * Handle removal of an HMTL template\n *\n * @function deleteHTML\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deleteHTML(filepath, section, store) {\n const newSection = section;\n\n utils.removeFile(\n newSection.referenceURI,\n 'template',\n filepath,\n store\n );\n\n delete newSection.templatePath;\n\n return store\n .setIn(\n ['sections', 'sectionsByPath', section.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n}\n\n/**\n * Handle update for a prototype file\n *\n * @function updatePrototype\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updatePrototype(filepath, store) {\n const file = path.parse(filepath);\n const content = fs.readFileSync(filepath, 'utf8');\n\n if (content) {\n const requirePath = utils.writeFile(\n file.name,\n 'prototype',\n filepath,\n content,\n store\n );\n\n return store.setIn(\n ['prototypes', file.name],\n requirePath\n );\n }\n\n console.log(`File ${file.base} could not be read`);\n return store;\n}\n\n/**\n * Handle removal of a prototype file\n *\n * @function deletePrototype\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deletePrototype(filepath, store) {\n const file = path.parse(filepath);\n const requirePath = utils.removeFile(\n file.name,\n 'prototype',\n filepath,\n store\n );\n\n return store.setIn(\n ['prototypes', file.name],\n requirePath\n );\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-html.js","/** @module cli/kss-handler */\n\nimport * as utils from './utils';\nimport { updateTemplate, deleteTemplate } from './handle-templates';\nimport { writeStore } from './require-templates';\n\nconst path = require('path');\nconst fs = require('fs-extra');\nconst parse = require('kss').parse;\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Handle update of a KSS section\n *\n * @function updateKSS\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updateKSS(filepath, store) {\n const kssSource = fs.readFileSync(filepath, 'utf8');\n const huron = store.get('config');\n const oldSection = utils.getSection(filepath, false, store) || {};\n const file = path.parse(filepath);\n let newStore = store;\n\n if (kssSource) {\n const styleguide = parse(kssSource, huron.get('kssOptions'));\n\n if (styleguide.data.sections.length) {\n const section = utils.normalizeSectionData(\n styleguide.data.sections[0]\n );\n\n if (section.reference && section.referenceURI) {\n // Update or add section data\n newStore = updateSectionData(\n filepath,\n section,\n oldSection,\n newStore\n );\n\n // Remove old section data if reference URI has changed\n if (oldSection &&\n oldSection.referenceURI &&\n oldSection.referenceURI !== section.referenceURI\n ) {\n newStore = unsetSection(oldSection, file, newStore, false);\n }\n\n writeStore(newStore);\n console.log(\n chalk.green(\n `KSS source in ${filepath} changed or added`\n )\n );\n return newStore;\n }\n\n console.log(\n chalk.magenta(\n `KSS section in ${filepath} is missing a section reference`\n )\n );\n return newStore;\n }\n\n console.log(chalk.magenta(`No KSS found in ${filepath}`));\n return newStore;\n }\n\n if (oldSection) {\n newStore = deleteKSS(filepath, oldSection, newStore);\n }\n\n console.log(chalk.red(`${filepath} not found or empty`)); // eslint-disable-line no-console\n return newStore;\n}\n\n/**\n * Handle removal of a KSS section\n *\n * @function deleteKSS\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deleteKSS(filepath, section, store) {\n const file = path.parse(filepath);\n\n if (section.reference && section.referenceURI) {\n // Remove section data from memory store\n return unsetSection(section, file, store, true);\n }\n\n return store;\n}\n\n/**\n * Update the sections store with new data for a specific section\n *\n * @function updateSectionData\n * @param {object} section - contains updated section data\n * @param {string} kssPath - path to KSS section\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nfunction updateSectionData(kssPath, section, oldSection, store) {\n const sectionFileInfo = path.parse(kssPath);\n const dataFilepath = path.join(\n sectionFileInfo.dir,\n `${sectionFileInfo.name}.json`\n );\n const isInline = null !== section.markup.match(/<\\/[^>]*>/);\n const newSort = sortSection(\n store.getIn(['sections', 'sorted']),\n section.reference,\n store.get('referenceDelimiter')\n );\n const newSection = Object.assign({}, oldSection, section);\n let newStore = store;\n\n // Required for reference from templates and data\n newSection.kssPath = kssPath;\n\n if (isInline) {\n // Set section value if inlineTempalte() returned a path\n newStore = updateInlineTemplate(\n kssPath,\n oldSection,\n newSection,\n newStore\n );\n } else {\n // Remove inline template, if it exists\n utils.removeFile(\n newSection.referenceURI,\n 'template',\n kssPath,\n store\n );\n // Update markup and data fields\n newStore = updateTemplateFields(\n sectionFileInfo,\n oldSection,\n newSection,\n newStore\n );\n }\n\n // Output section description\n newStore = updateDescription(\n kssPath,\n oldSection,\n newSection,\n newStore\n );\n\n // Output section data to a JSON file\n newSection.sectionPath = utils.writeSectionData(\n newStore,\n newSection,\n dataFilepath\n );\n\n // Update section sorting\n return newStore\n .setIn(\n ['sections', 'sorted'],\n newSort\n )\n .setIn(\n ['sections', 'sectionsByPath', kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n}\n\n/**\n * Handle detection and output of inline templates, which is markup written\n * in the KSS documentation itself as opposed to an external file\n *\n * @function updateInlineTemplate\n * @param {string} oldSection - previous iteration of KSS data, if updated\n * @param {object} section - KSS section data\n * @return {object} updated data store with new template path info\n */\nfunction updateInlineTemplate(filepath, oldSection, section, store) {\n const newSection = section;\n const newStore = store;\n\n // If we have inline markup\n if (fieldShouldOutput(oldSection, section, 'markup')) {\n newSection.templatePath = utils.writeFile(\n section.referenceURI,\n 'template',\n filepath,\n section.markup,\n store\n );\n newSection.templateContent = section.markup;\n\n return newStore\n .setIn(\n ['sections', 'sectionsByPath', filepath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle output of section description\n *\n * @function updateDescription\n * @param {string} oldSection - previous iteration of KSS data, if updated\n * @param {object} section - KSS section data\n * @return {object} updated data store with new descripton path info\n */\nfunction updateDescription(filepath, oldSection, section, store) {\n const newSection = section;\n const newStore = store;\n\n // If we don't have previous KSS or the KSS has been updated\n if (fieldShouldOutput(oldSection, section, 'description')) {\n // Write new description\n newSection.descriptionPath = utils.writeFile(\n section.referenceURI,\n 'description',\n filepath,\n section.description,\n store\n );\n\n return newStore\n .setIn(\n ['sections', 'sectionsByPath', filepath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle Data and Markup fields\n *\n * @function updateTemplateFields\n * @param {string} file - File data for KSS file from path.parse()\n * @param {object} oldSection - outdated KSS data\n * @param {object} section - KSS section data\n * @param {object} store - memory store\n * @return {object} KSS section data with updated asset paths\n */\nfunction updateTemplateFields(file, oldSection, section, store) {\n const kssPath = path.format(file);\n const newSection = section;\n let filepath = '';\n let oldFilepath = '';\n let newStore = store;\n\n ['data', 'markup'].forEach((field) => {\n if (newSection[field]) {\n if (oldSection[field]) {\n oldFilepath = path.join(file.dir, oldSection[field]);\n newStore = deleteTemplate(\n oldFilepath,\n oldSection,\n newStore\n );\n }\n\n filepath = path.join(file.dir, newSection[field]);\n newStore = updateTemplate(\n filepath,\n newSection,\n newStore\n );\n } else {\n delete newSection[field];\n newStore = newStore\n .setIn(\n ['sections', 'sectionsByPath', kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n }\n });\n\n return newStore;\n}\n\n/**\n * Remove a section from the memory store\n *\n * @function unsetSection\n * @param {object} section - contains updated section data\n * @param {string} file - file object from path.parse()\n * @param {object} store - memory store\n * @param {bool} removed - has the file been removed or just the section information changed?\n * @return {object} updated data store with new descripton path info\n */\nfunction unsetSection(section, file, store, removed) {\n const sorted = store.getIn(['sections', 'sorted']);\n const kssPath = path.format(file);\n const dataFilepath = path.join(file.dir, `${file.name}.json`);\n const isInline = section.markup &&\n null !== section.markup.match(/<\\/[^>]*>/);\n const newSort = unsortSection(\n sorted,\n section.reference,\n store.get('referenceDelimiter')\n );\n let newStore = store;\n\n // Remove old section data\n utils.removeFile(\n section.referenceURI,\n 'section',\n dataFilepath,\n newStore\n );\n\n // Remove associated inline template\n if (isInline) {\n utils.removeFile(section.referenceURI, 'template', kssPath, newStore);\n }\n\n // Remove description template\n utils.removeFile(section.referenceURI, 'description', kssPath, newStore);\n\n // Remove data from sectionsByPath if file has been removed\n if (removed) {\n newStore = newStore.deleteIn(['sections', 'sectionsByPath', kssPath]);\n }\n\n return newStore\n .deleteIn(['sections', 'sectionsByURI', section.referenceURI])\n .setIn(['sections', 'sorted'], newSort);\n}\n\n/**\n * Sort sections and subsections\n *\n * @function sortSection\n * @param {object} sorted - currently sorted sections\n * @param {string} reference - reference URI of section to sort\n * @return {object} updated data store with new descripton path info\n */\nfunction sortSection(sorted, reference, delimiter) {\n const parts = reference.split(delimiter);\n const newSort = sorted[parts[0]] || {};\n const newSorted = sorted;\n\n if (1 < parts.length) {\n const newParts = parts.filter((part, idx) => 0 !== idx);\n newSorted[parts[0]] = sortSection(\n newSort,\n newParts.join(delimiter),\n delimiter\n );\n } else {\n newSorted[parts[0]] = newSort;\n }\n\n return newSorted;\n}\n\n/**\n * Remove a section from the sorted sections\n *\n * @function unsortSection\n * @param {object} sorted - currently sorted sections\n * @param {string} reference - reference URI of section to sort\n * @return {object} updated data store with new descripton path info\n */\nfunction unsortSection(sorted, reference, delimiter) {\n const parts = reference.split(delimiter);\n const subsections = Object.keys(sorted[parts[0]]);\n const newSorted = sorted;\n\n if (subsections.length) {\n if (1 < parts.length) {\n const newParts = parts.filter((part, idx) => 0 !== idx);\n newSorted[parts[0]] = unsortSection(\n newSorted[parts[0]],\n newParts.join(delimiter),\n delimiter\n );\n }\n } else {\n delete newSorted[parts[0]];\n }\n\n return newSorted;\n}\n\n/**\n * Compare a KSS field between old and new KSS data to see if we need to output\n * a new module for that field\n *\n * @function fieldShouldOutput\n * @param {object} oldSection - currently sorted sections\n * @param {object} newSection - reference URI of section to sort\n * @param {string} field - KSS field to check\n * @return {bool} output a new module for the KSS field\n */\nfunction fieldShouldOutput(oldSection, newSection, field) {\n return (oldSection &&\n (oldSection[field] !== newSection[field] ||\n oldSection.referenceURI !== newSection.referenceURI)\n ) ||\n ! oldSection;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-kss.js","import { Map } from 'immutable';\nimport generateConfig from './generate-config';\n// Create initial data structure\n\n// Merge Huron default webpack config with user config\nconst config = generateConfig();\n\n// Make sure the kss option is represented as an array\nconfig.huron.kss = Array.isArray(config.huron.kss) ?\n config.huron.kss :\n [config.huron.kss];\n\n/* eslint-disable */\n/**\n * Initial structure for immutable data store\n *\n * @global\n */\nconst dataStructure = Map({\n types: [\n 'template',\n 'data',\n 'description',\n 'section',\n 'prototype',\n 'sections-template',\n ],\n config: Map(config.huron),\n sections: Map({\n sectionsByPath: Map({}),\n sectionsByURI: Map({}),\n sorted: {},\n }),\n templates: Map({}),\n prototypes: Map({}),\n sectionTemplatePath: '',\n referenceDelimiter: '.',\n});\n/* eslint-enable */\n\nexport { dataStructure, config };\n\n\n\n// WEBPACK FOOTER //\n// src/cli/huron-store.js","// Necessary to remove require statement from Webpack processing preserve it in output\n/* eslint-disable import/no-dynamic-require, global-require */\nexport default function requireExternal(requirePath) {\n return require(requirePath);\n}\n/* eslint-enable */\n\n\n\n// WEBPACK FOOTER //\n// src/cli/require-external.js","/** @module cli/webpack-server */\n\nimport program from './parse-args';\n\nconst webpack = require('webpack');\nconst WebpackDevServer = require('webpack-dev-server');\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Spin up webpack-dev-server or, if production flag is set, run webpack a single time\n *\n * @function startWebpack\n * @param {object} config - webpack configuration, preprocessed by {@link module:cli/generate-config generateConfig}\n * @see {@link module:cli/generate-config generateConfig}\n */\nexport default function startWebpack(config) {\n const huron = config.huron;\n const webpackConfig = config.webpack;\n const compiler = webpack(webpackConfig);\n\n if (program.progress) {\n compiler.apply(\n new webpack.ProgressPlugin(\n (percentage, msg) => {\n console.log(`${(percentage * 100)}% `, msg);\n }\n )\n );\n }\n\n if (program.production) {\n compiler.run((err, stats) => {\n const info = stats.toJson();\n\n if (err) {\n console.log(err);\n }\n\n if (stats.hasErrors()) {\n console.error(\n chalk.red(\n 'Webpack encountered errors during compile: ',\n info.errors\n )\n );\n }\n\n if (stats.hasWarnings()) {\n console.error(\n chalk.yellow(\n 'Webpack encountered warnings during compile: ', info.warnings\n )\n );\n }\n });\n } else {\n const server = new WebpackDevServer(compiler, {\n hot: true,\n quiet: false,\n noInfo: false,\n stats: {\n colors: true,\n hash: false,\n version: false,\n assets: false,\n chunks: false,\n modules: false,\n reasons: false,\n children: false,\n source: false,\n },\n contentBase: huron.root,\n publicPath: `http://localhost:${huron.port}/${huron.root}`,\n });\n server.listen(\n huron.port,\n 'localhost',\n (err) => {\n if (err) {\n return console.log(err);\n }\n\n console.log(`Listening at http://localhost:${huron.port}/`);\n return true;\n }\n );\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/server.js","const path = require('path');\n\nmodule.exports = {\n css: [],\n entry: 'huron',\n js: [],\n kss: 'css/',\n kssExtension: '.css',\n kssOptions: {\n multiline: true,\n markdown: true,\n custom: ['data'],\n },\n output: 'partials',\n port: 8080,\n prototypes: ['index'],\n root: 'dist/',\n sectionTemplate: path.join(__dirname, '../../templates/section.hbs'),\n templates: {\n rule: {\n test: /\\.(hbs|handlebars)$/,\n use: 'handlebars-template-loader',\n },\n extension: '.hbs',\n },\n window: {},\n};\n\n\n\n// WEBPACK FOOTER //\n// src/default-config/huron.config.js","const webpack = require('webpack');\nconst path = require('path');\n\nmodule.exports = {\n entry: {},\n output: {\n // path: [huron root directory],\n filename: '[name].js',\n chunkFilename: '[name].chunk.min.js',\n },\n plugins: [\n new webpack.HotModuleReplacementPlugin(),\n new webpack.NamedModulesPlugin(),\n ],\n resolve: {\n modulesDirectories: [\n path.resolve(__dirname, '../src/js'),\n ],\n },\n resolveLoader: {\n modulesDirectories: [\n 'web_loaders',\n 'web_modules',\n 'node_loaders',\n 'node_modules',\n path.resolve(__dirname, '../node_modules'),\n ],\n },\n module: {\n rules: [\n {\n test: /\\.html?$/,\n use: [\n {\n loader: 'dom-loader',\n options: {\n tag: 'dom-module',\n },\n },\n 'html-loader',\n ],\n // include: ['path/to/templates']\n },\n ],\n },\n};\n\n\n\n// WEBPACK FOOTER //\n// src/default-config/webpack.config.js","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 18\n// module chunks = 0","module.exports = require(\"gaze\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"gaze\"\n// module id = 19\n// module chunks = 0","module.exports = require(\"html-webpack-plugin\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"html-webpack-plugin\"\n// module id = 20\n// module chunks = 0","module.exports = require(\"immutable\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"immutable\"\n// module id = 21\n// module chunks = 0","module.exports = require(\"kss\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kss\"\n// module id = 22\n// module chunks = 0","module.exports = require(\"url\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"url\"\n// module id = 23\n// module chunks = 0","module.exports = require(\"webpack-dev-server\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack-dev-server\"\n// module id = 24\n// module chunks = 0"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;A;;;;AChEA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;ACcA;AAkBA;AAqCA;AAqCA;AAcA;AAkBA;AAyBA;AA4CA;AAyCA;AA0BA;AAyBA;AA3SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAGA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AAGA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;;AAFA;AAKA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;AC5TA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;ACzDA;;;;;;;;;;;;ACgBA;AA0DA;AACA;AA1EA;AACA;AADA;AACA;;;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAUA;;;;;;;;;;;;ACnGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;;;;;;;;;AASA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;;AAEA;;;;;;;;;;;;AAYA;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;AAhBA;AACA;AA0CA;;;;;;;;;;;;;AAAA;AACA;AAcA;AACA;AACA;AAGA;AAHA;AAMA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAHA;AAMA;;;;;;;;;ACnHA;AACA;AAAA;AACA;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACxGA;AA2CA;AA+DA;AACA;AAnIA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;AADA;AACA;;;AACA;AAbA;AACA;AACA;AAYA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxBA;AACA;AA0BA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxCA;AACA;AA0CA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AArCA;AACA;AAuCA;AACA;;;;;;;;;;;;ACtJA;AACA;AA9BA;AACA;;;AAAA;AACA;;;;;AAJA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAHA;AACA;AAOA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAZA;AAcA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC7RA;AA0CA;AA+BA;AA+BA;AACA;AAvHA;AACA;AADA;AACA;;;AACA;AACA;AAAA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AASA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AAMA;AAIA;;;;;;;;;;;;ACjHA;AAsEA;AACA;AAxFA;AACA;AADA;AACA;AAAA;AACA;AAAA;AACA;;;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAMA;AACA;AAIA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AAIA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAMA;AACA;AAMA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAKA;AACA;AAaA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AASA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AAKA;;;;;;;;;;;;;;AC9aA;AACA;AAAA;AACA;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;AAKA;AACA;AAQA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AAlBA;AAoBA;AACA;AACA;AAAA;;;;;;;;;;;ACtCA;AAFA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACUA;AACA;AAdA;AACA;;;;;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AAhBA;AAkBA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;ACvFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AALA;AAOA;AAvBA;;;;;;;;;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AAIA;AACA;AADA;AAKA;AACA;AADA;AASA;AACA;AAEA;AACA;AAEA;AACA;AACA;AADA;AAFA;AAQA;AAXA;AAFA;AAzBA;;;;;;ACHA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;A","sourceRoot":""}
\ No newline at end of file
+{"version":3,"file":"huron-cli.js","sources":["webpack:///webpack/bootstrap 69c5fe6b13e438ab2726","webpack:///external \"path\"","webpack:///external \"chalk\"","webpack:///external \"fs-extra\"","webpack:///src/cli/parse-args.js","webpack:///src/cli/utils.js","webpack:///external \"webpack\"","webpack:///src/cli/handle-templates.js","webpack:///src/cli/require-templates.js","webpack:///src/cli/huron-cli.js","webpack:///src/cli/actions.js","webpack:///src/cli/generate-config.js","webpack:///src/cli/handle-html.js","webpack:///src/cli/handle-kss.js","webpack:///src/cli/huron-store.js","webpack:///src/cli/require-external.js","webpack:///src/cli/server.js","webpack:///src/default-config/huron.config.js","webpack:///src/default-config/webpack.config.js","webpack:///external \"commander\"","webpack:///external \"gaze\"","webpack:///external \"html-webpack-plugin\"","webpack:///external \"immutable\"","webpack:///external \"kss\"","webpack:///external \"url\"","webpack:///external \"webpack-dev-server\""],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"../\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 25);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 69c5fe6b13e438ab2726","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 0\n// module chunks = 0","module.exports = require(\"chalk\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"chalk\"\n// module id = 1\n// module chunks = 0","module.exports = require(\"fs-extra\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"fs-extra\"\n// module id = 2\n// module chunks = 0","/** @module cli/parse-arguments */\n/* eslint-disable space-unary-ops */\n\n// Requires\n/** @global */\nconst program = require('commander'); // Easy program flags\nconst path = require('path');\n\nexport default program;\n\n/**\n * Process huron CLI arguments\n *\n * @function parseArgs\n * @example node huron/dist/cli/huron-cli.js --config 'client/config/webpack.config.js' --production\n */\nfunction parseArgs() {\n const envArg = {};\n\n process.argv = process.argv.filter((arg) => {\n if (-1 !== arg.indexOf('--env')) {\n const envParts = arg\n .split('.')[1]\n .split('=');\n\n envArg[envParts[0]] = envParts[1] || true;\n return false;\n }\n\n return true;\n });\n\n program.version('1.0.1')\n .option(\n '-c, --huron-config [huronConfig]',\n '[huronConfig] for all huron options',\n path.resolve(__dirname, '../default-config/huron.config.js')\n )\n .option(\n '-w, --webpack-config [webpackConfig]',\n '[webpackConfig] for all webpack options',\n path.resolve(__dirname, '../default-config/webpack.config.js')\n )\n .option('-p, --production', 'compile assets once for production');\n\n program.env = envArg;\n\n // Only parse if we're not running tests\n if (\n ! process.env.npm_lifecycle_event ||\n 'test' !== process.env.npm_lifecycle_event\n ) {\n program.parse(process.argv);\n }\n}\n\nparseArgs();\n/* eslint-enable */\n\n\n\n// WEBPACK FOOTER //\n// src/cli/parse-args.js","/** @module cli/utilities */\n\nconst cwd = process.cwd(); // Current working directory\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Ensure predictable data structure for KSS section data\n *\n * @function normalizeSectionData\n * @param {object} section - section data\n * @return {object} section data\n */\nexport function normalizeSectionData(section) {\n const data = section.data || section;\n\n if (! data.referenceURI || '' === data.referenceURI) {\n data.referenceURI = section.referenceURI();\n }\n\n return data;\n}\n\n/**\n * Ensure predictable data structure for KSS section data\n *\n * @function writeSectionData\n * @param {object} store - data store\n * @param {object} section - section data\n * @param {string} sectionPath - output destination for section data file\n */\nexport function writeSectionData(store, section, sectionPath = false) {\n let outputPath = sectionPath;\n let sectionFileInfo;\n\n if (! outputPath && {}.hasOwnProperty.call(section, 'kssPath')) {\n sectionFileInfo = path.parse(section.kssPath);\n outputPath = path.join(\n sectionFileInfo.dir,\n `${sectionFileInfo.name}.json`\n );\n }\n\n // Output section data\n if (outputPath) {\n return writeFile(\n section.referenceURI,\n 'section',\n outputPath,\n JSON.stringify(section),\n store\n );\n }\n\n console.warn( // eslint-disable-line no-console\n chalk.red(`Failed to write section data for ${section.referenceURI}`)\n );\n return false;\n}\n\n/**\n * Find .json from a template file or vice versa\n *\n * @function getTemplateDataPair\n * @param {object} file - file object from path.parse()\n * @param {object} section - KSS section data\n * @return {string} relative path to module JSON file\n */\nexport function getTemplateDataPair(file, section, store) {\n const huron = store.get('config');\n const kssDir = matchKssDir(file.dir, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const partnerType = '.json' === file.ext ? 'template' : 'data';\n const partnerExt = '.json' === file.ext ?\n huron.get('templates').extension :\n '.json';\n\n const pairPath = path.join(\n componentPath,\n generateFilename(\n section.referenceURI,\n partnerType,\n partnerExt,\n store\n )\n );\n\n return `./${pairPath}`;\n }\n\n return false;\n}\n\n/**\n * Normalize a section title for use as a filename\n *\n * @function normalizeHeader\n * @param {string} header - section header extracted from KSS documentation\n * @return {string} modified header, lowercase and words separated by dash\n */\nexport function normalizeHeader(header) {\n return header\n .toLowerCase()\n .replace(/\\s?\\W\\s?/g, '-');\n}\n\n/**\n * Wrap html in required template tags\n *\n * @function wrapMarkup\n * @param {string} content - html or template markup\n * @param {string} templateId - id of template (should be section reference)\n * @return {string} modified HTML\n */\nexport function wrapMarkup(content, templateId) {\n return `\n\n${content}\n\n\\n`;\n}\n\n/**\n * Generate a filename based on referenceURI, type and file object\n *\n * @function generateFilename\n * @param {string} id - The name of the file (with extension).\n * @param {string} type - the type of file output\n * @param {object} ext - file extension\n * @param {store} store - data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function generateFilename(id, type, ext, store) {\n // Type of file and its corresponding extension(s)\n const types = store.get('types');\n const outputExt = '.scss' !== ext ? ext : '.html';\n\n /* eslint-disable */\n if (-1 === types.indexOf(type)) {\n console.log(`Huron data ${type} does not exist`);\n return false;\n }\n /* eslint-enable */\n\n return `${id}-${type}${outputExt}`;\n}\n\n/**\n * Copy an HTML file into the huron output directory.\n *\n * @function writeFile\n * @param {string} id - The name of the file (with extension).\n * @param {string} content - The content of the file to write.\n * @param {string} type - the type of file output\n * @param {object} store - The data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function writeFile(id, type, filepath, content, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n const filename = generateFilename(id, type, file.ext, store);\n const kssDir = matchKssDir(filepath, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const outputRelative = path.join(\n huron.get('output'),\n componentPath,\n `${filename}`\n );\n const outputPath = path.resolve(cwd, huron.get('root'), outputRelative);\n let newContent = content;\n\n if ('data' !== type && 'section' !== type) {\n newContent = wrapMarkup(content, id);\n }\n\n try {\n fs.outputFileSync(outputPath, newContent);\n console.log(chalk.green(`Writing ${outputRelative}`)); // eslint-disable-line no-console\n } catch (e) {\n console.log(chalk.red(`Failed to write ${outputRelative}`)); // eslint-disable-line no-console\n }\n\n return `./${outputRelative.replace(`${huron.get('output')}/`, '')}`;\n }\n\n return false;\n}\n\n/**\n * Delete a file in the huron output directory\n *\n * @function removeFile\n * @param {string} filename - The name of the file (with extension).\n * @param {object} store - The data store\n * @return {string} Path to output file, relative to ouput dir (can be use in require statements)\n */\nexport function removeFile(id, type, filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n const filename = generateFilename(id, type, file.ext, store);\n const kssDir = matchKssDir(filepath, huron);\n\n if (kssDir) {\n const componentPath = path.relative(\n path.resolve(cwd, kssDir),\n file.dir\n );\n const outputRelative = path.join(\n huron.get('output'),\n componentPath,\n `${filename}`\n );\n const outputPath = path.resolve(cwd, huron.get('root'), outputRelative);\n\n try {\n fs.removeSync(outputPath);\n console.log(chalk.green(`Removing ${outputRelative}`)); // eslint-disable-line no-console\n } catch (e) {\n console.log( // eslint-disable-line no-console\n chalk.red(`${outputRelative} does not exist or cannot be deleted`)\n );\n }\n\n return `./${outputRelative.replace(`${huron.get('output')}/`, '')}`;\n }\n\n return false;\n}\n\n/**\n * Write a template for sections\n *\n * @function writeSectionTemplate\n * @param {string} filepath - the original template file\n * @param {object} store - data store\n * @return {object} updated store\n */\nexport function writeSectionTemplate(filepath, store) {\n const huron = store.get('config');\n const sectionTemplate = wrapMarkup(fs.readFileSync(filepath, 'utf8'));\n const componentPath = './huron-assets/section.hbs';\n const output = path.join(\n cwd,\n huron.get('root'),\n componentPath\n );\n\n // Move huron script and section template into huron root\n fs.outputFileSync(output, sectionTemplate);\n console.log(chalk.green(`writing section template to ${output}`)); // eslint-disable-line no-console\n\n return store.set('sectionTemplatePath', componentPath);\n}\n\n/**\n * Request for section data based on section reference\n *\n * @function writeSectionTemplate\n * @param {string} search - key on which to match section\n * @param {field} string - field in which to look to determine section\n * @param {obj} store - sections memory store\n */\nexport function getSection(search, field, store) {\n const sectionValues = store\n .getIn(['sections', 'sectionsByPath'])\n .valueSeq();\n let selectedSection = false;\n\n if (field) {\n selectedSection = sectionValues\n .filter((value) => value[field] === search)\n .get(0);\n } else {\n selectedSection = store.getIn(['sections', 'sectionsByPath', search]);\n }\n\n return selectedSection;\n}\n\n/**\n * Find which configured KSS directory a filepath exists in\n *\n * @function matchKssDir\n * @param {string} filepath - filepath to search for\n * @param {object} huron - huron configuration\n * @return {string} kssMatch - relative path to KSS directory\n */\nexport function matchKssDir(filepath, huron) {\n const kssSource = huron.get('kss');\n /* eslint-disable space-unary-ops */\n // Include forward slash in our test to make sure we're matchin a directory, not a file extension\n const kssMatch = kssSource.filter((dir) => filepath.includes(`/${dir}`));\n /* eslint-enable space-unary-ops */\n\n if (kssMatch.length) {\n return kssMatch[0];\n }\n\n console.error(\n chalk.red(`filepath ${filepath} does not exist in any\n of the configured KSS directories`)\n );\n\n return false;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/utils.js","module.exports = require(\"webpack\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack\"\n// module id = 5\n// module chunks = 0","/** @module cli/template-handler */\nimport * as utils from './utils';\n\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk');\n\n/**\n * Handle update of a template or data (json) file\n *\n * @function updateTemplate\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated memory store\n */\nexport function updateTemplate(filepath, section, store) {\n const file = path.parse(filepath);\n const pairPath = utils.getTemplateDataPair(file, section, store);\n const type = '.json' === file.ext ? 'data' : 'template';\n const newSection = section;\n const newStore = store;\n let content = false;\n\n try {\n content = fs.readFileSync(filepath, 'utf8');\n } catch (e) {\n console.log(chalk.red(`${filepath} does not exist`));\n }\n\n if (content) {\n const requirePath = utils.writeFile(\n newSection.referenceURI,\n type,\n filepath,\n content,\n newStore\n );\n newSection[`${type}Path`] = requirePath;\n\n if ('template' === type) {\n newSection.templateContent = content;\n\n // Rewrite section data with template content\n newSection.sectionPath = utils.writeSectionData(newStore, newSection);\n }\n\n return newStore\n .setIn(\n ['templates', requirePath],\n pairPath\n )\n .setIn(\n ['sections', 'sectionsByPath', newSection.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle removal of a template or data (json) file\n *\n * @function deleteTemplate\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated memory store\n */\nexport function deleteTemplate(filepath, section, store) {\n const file = path.parse(filepath);\n const type = '.json' === file.ext ? 'data' : 'template';\n const newSection = section;\n const newStore = store;\n\n // Remove partner\n const requirePath = utils.removeFile(\n newSection.referenceURI,\n type,\n filepath,\n newStore\n );\n delete newSection[`${type}Path`];\n\n return newStore\n .deleteIn(['templates', requirePath])\n .setIn(\n ['sections', 'sectionsByPath', newSection.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-templates.js","/** @module cli/require-templates */\n\nconst path = require('path');\nconst fs = require('fs-extra');\n\nconst cwd = process.cwd();\nconst huronScript = fs.readFileSync(\n path.join(__dirname, '../web/huron.js'),\n 'utf8'\n);\n\n/**\n * Write code for requiring all generated huron assets\n * Note: prepended and appended code in this file should roughly follow es5 syntax for now,\n * as it will not pass through the Huron internal babel build nor can we assume the user is\n * working with babel.\n *\n * @function requireTemplates\n * @param {object} store - memory store\n */\nexport const requireTemplates = function requireTemplates(store) {\n const huron = store.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n const requireRegex = new RegExp(`\\\\.html|\\\\.json|\\\\${\n huron.get('templates').extension\n }$`);\n const requirePath = `'../${huron.get('output')}'`;\n\n // Initialize templates, js, css and Hot Module Replacement acceptance logic\n const prepend = `\nvar store = require('./huron-store.js');\nvar sectionTemplate = require('./section.hbs');\nvar assets = require.context(${requirePath}, true, ${requireRegex});\nvar modules = {};\n\nmodules['${store.get('sectionTemplatePath')}'] = sectionTemplate;\n\nassets.keys().forEach(function(key) {\n modules[key] = assets(key);\n});\n\nif (module.hot) {\n // Hot Module Replacement for huron components (json, hbs, html)\n module.hot.accept(\n assets.id,\n () => {\n var newAssets = require.context(\n ${requirePath},\n true,\n ${requireRegex}\n );\n var newModules = newAssets.keys()\n .map((key) => {\n return [key, newAssets(key)];\n })\n .filter((newModule) => {\n return modules[newModule[0]] !== newModule[1];\n });\n\n updateStore(require('./huron-store.js'));\n\n newModules.forEach((module) => {\n modules[module[0]] = module[1];\n hotReplace(module[0], module[1], modules);\n });\n }\n );\n\n // Hot Module Replacement for sections template\n module.hot.accept(\n './section.hbs',\n () => {\n var newSectionTemplate = require('./section.hbs');\n modules['${store.get('sectionTemplatePath')}'] = newSectionTemplate;\n hotReplace(\n './huron-assets/section.hbs',\n newSectionTemplate,\n modules\n );\n }\n );\n\n // Hot Module Replacement for data store\n module.hot.accept(\n './huron-store.js',\n () => {\n updateStore(require('./huron-store.js'));\n }\n );\n}\\n`;\n\n const append = `\nfunction hotReplace(key, module, modules) {\n insert.modules = modules;\n if (key === store.sectionTemplatePath) {\n insert.cycleSections();\n } else {\n insert.inserted = [];\n insert.loadModule(key, module, false);\n }\n};\n\nfunction updateStore(newStore) {\n insert.store = newStore;\n}\\n`;\n\n // Write the contents of this script.\n // @todo lint this file.\n fs.outputFileSync(\n path.join(outputPath, 'huron.js'),\n `/*eslint-disable*/\\n\n${prepend}\\n\\n${huronScript}\\n\\n${append}\\n\n/*eslint-enable*/\\n`\n );\n};\n\n/**\n * Output entire data store to a JS object and handle if any KSS data has changed\n *\n * @function writeStore\n * @param {object} store - memory store\n * @param {string} changed - filepath of changed KSS section, if applicable\n */\nexport const writeStore = function writeStore(store) {\n const huron = store.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n\n // Write updated data store\n // @todo lint this file.\n fs.outputFileSync(\n path.join(outputPath, 'huron-store.js'),\n `/*eslint-disable*/\n module.exports = ${JSON.stringify(store.toJSON())}\n /*eslint-disable*/\\n`\n );\n};\n\n\n\n\n// WEBPACK FOOTER //\n// src/cli/require-templates.js","// Local imports\nimport { initFiles, updateFile, deleteFile } from './actions';\nimport { requireTemplates, writeStore } from './require-templates';\nimport program from './parse-args';\nimport startWebpack from './server';\nimport { dataStructure, config } from './huron-store';\n\n// Modules\nconst path = require('path');\nconst Gaze = require('gaze').Gaze;\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Huron configuration object\n *\n * @global\n */\nconst huron = dataStructure.get('config');\n\n/**\n * Available file extensions. Extensions should not include the leading '.'\n *\n * @global\n */\nconst extensions = [\n huron.get('kssExtension'),\n huron.get('templates').extension,\n 'html',\n 'json',\n].map((extension) => extension.replace('.', ''));\n\n// Generate watch list for Gaze, start gaze\nconst gazeWatch = [];\n\n// Push KSS source directories and section template to Gaze\ngazeWatch.push(path.resolve(__dirname, huron.get('sectionTemplate')));\nhuron.get('kss').forEach((sourceDir) => {\n let gazeDir = sourceDir;\n\n /* eslint-disable space-unary-ops */\n if ('/' === sourceDir.slice(-1)) {\n gazeDir = sourceDir.slice(0, -1);\n }\n /* eslint-enable space-unary-ops */\n\n gazeWatch.push(\n `${gazeDir}/**/*.+(${extensions.join('|')})`\n );\n});\n\n/**\n * Gaze instance for watching all files, including KSS, html, hbs/template, and JSON\n *\n * @global\n */\nconst gaze = new Gaze(gazeWatch);\n\n/**\n * Initialize data store with files from gaze and original data structure\n *\n * @global\n */\nconst store = initFiles(gaze.watched(), dataStructure);\n\nrequireTemplates(store);\nwriteStore(store);\n\nif (! program.production) {\n /** @module cli/gaze */\n let newStore = store;\n\n /**\n * Anonymous handler for Gaze 'changed' event indicating a file has changed\n *\n * @callback changed\n * @listens gaze:changed\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('changed', (filepath) => {\n newStore = updateFile(filepath, newStore);\n console.log(chalk.green(`${filepath} updated!`));\n });\n\n /**\n * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories\n *\n * @callback added\n * @listens gaze:added\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('added', (filepath) => {\n newStore = updateFile(filepath, newStore);\n writeStore(newStore);\n console.log(chalk.blue(`${filepath} added!`));\n });\n\n /**\n * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed\n *\n * @callback renamed\n * @listens gaze:renamed\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('renamed', (newPath, oldPath) => {\n newStore = deleteFile(oldPath, newStore);\n newStore = updateFile(newPath, newStore);\n writeStore(newStore);\n console.log(chalk.blue(`${newPath} added!`));\n });\n\n /**\n * Anonymous handler for Gaze 'deleted' event indicating a file has been removed\n *\n * @callback deleted\n * @listens gaze:deleted\n * @param {string} filepath - absolute path of changed file\n */\n gaze.on('deleted', (filepath) => {\n newStore = deleteFile(filepath, newStore);\n writeStore(newStore);\n console.log(chalk.red(`${filepath} deleted`));\n });\n} else {\n gaze.close();\n}\n\n// Start webpack or build for production\nstartWebpack(config);\n\nif (module.hot) {\n module.hot.accept();\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/huron-cli.js","/** @module cli/actions */\n\n// Imports\nimport {\n updateHTML,\n deleteHTML,\n updatePrototype,\n deletePrototype,\n} from './handle-html';\nimport { updateTemplate, deleteTemplate } from './handle-templates';\nimport { updateKSS, deleteKSS } from './handle-kss';\nimport * as utils from './utils';\n\n// Requires\nconst path = require('path');\nconst chalk = require('chalk'); // Colorize terminal output\n\n// EXPORTED FUNCTIONS\n\n/**\n * Recursively loop through initial watched files list from Gaze.\n *\n * @param {object} data - object containing directory and file paths\n * @param {object} store - memory store\n * @param {object} huron - huron configuration options\n * @return {object} newStore - map object of entire data store\n */\nexport function initFiles(data, store, depth = 0) {\n const type = Object.prototype.toString.call(data);\n let newStore = store;\n let info;\n let files;\n\n switch (type) {\n case '[object Object]':\n files = Object.keys(data);\n newStore = files.reduce(\n (prevStore, file) => initFiles(data[file], prevStore, depth),\n newStore\n );\n break;\n\n case '[object Array]':\n newStore = data.reduce(\n (prevStore, file) => initFiles(file, prevStore, depth),\n newStore\n );\n break;\n\n case '[object String]':\n info = path.parse(data);\n if (info.ext) {\n newStore = updateFile(data, store);\n }\n break;\n\n default:\n break;\n }\n\n return newStore;\n}\n\n/**\n * Logic for updating and writing file information based on file type (extension)\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n * @return {object} store - map object of map object of entire data store\n */\nexport function updateFile(filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n let field;\n let section;\n\n if (filepath.includes(huron.get('sectionTemplate'))) {\n return utils.writeSectionTemplate(filepath, store);\n }\n\n switch (file.ext) {\n // Plain HTML template, external\n case '.html':\n section = utils.getSection(file.base, 'markup', store);\n\n if (section) {\n return updateHTML(filepath, section, store);\n } else if (\n - 1 !== file.dir.indexOf('prototypes') &&\n - 1 !== file.name.indexOf('prototype-')\n ) {\n return updatePrototype(filepath, store);\n }\n\n console.log(chalk.red(`Failed to write file: ${file.name}`));\n break;\n\n // Handlebars template, external\n case huron.get('templates').extension:\n case '.json':\n field = ('.json' === file.ext) ? 'data' : 'markup';\n section = utils.getSection(file.base, field, store);\n\n if (section) {\n return updateTemplate(filepath, section, store);\n }\n\n console.log( // eslint-disable-line no-console\n chalk.red(`Could not find associated KSS section for ${filepath}`)\n );\n break;\n\n // KSS documentation (default extension is `.css`)\n // Will also output a template if markup is inline\n // Note: inline markup does _not_ support handlebars currently\n case huron.get('kssExtension'):\n return updateKSS(filepath, store);\n\n // This should never happen if Gaze is working properly\n default:\n return store;\n }\n\n return store;\n}\n\n/**\n * Logic for deleting file information and files based on file type (extension)\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n * @return {object} newStore - map object of map object of entire data store\n */\nexport function deleteFile(filepath, store) {\n const huron = store.get('config');\n const file = path.parse(filepath);\n let field = '';\n let section = null;\n let newStore = store;\n\n switch (file.ext) {\n // Plain HTML template, external\n case '.html':\n section = utils.getSection(file.base, 'markup', store);\n\n if (section) {\n newStore = deleteHTML(filepath, section, store);\n } else if (\n - 1 !== file.dir.indexOf('prototypes') &&\n - 1 !== file.name.indexOf('prototype-')\n ) {\n newStore = deletePrototype(filepath, store);\n }\n break;\n\n case huron.get('templates').extension:\n case '.json':\n field = ('.json' === file.ext) ? 'data' : 'markup';\n section = utils.getSection(file.base, field, store);\n\n if (section) {\n newStore = deleteTemplate(filepath, section, store);\n }\n break;\n\n case huron.get('kssExtension'):\n section = utils.getSection(filepath, false, store);\n\n if (section) {\n newStore = deleteKSS(filepath, section, store);\n }\n break;\n\n default:\n console.warn( // eslint-disable-line no-console\n chalk.red(`Could not delete: ${file.name}`)\n );\n break;\n }\n\n return newStore;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/actions.js","/** @module cli/generate-config */\nimport program from './parse-args';\nimport requireExternal from './require-external';\n\nconst cwd = process.cwd();\nconst path = require('path');\nconst url = require('url');\nconst fs = require('fs-extra');\nconst webpack = require('webpack');\nconst HTMLWebpackPlugin = require('html-webpack-plugin');\nconst defaultWebpack = require('../default-config/webpack.config');\nconst defaultHuron = require('../default-config/huron.config');\n\n// Require configs passed in by user from CLI\nlet defaultConfig = false;\nconst localConfigPath = ! path.isAbsolute(program.webpackConfig) ?\n path.join(cwd, program.webpackConfig) :\n program.webpackConfig;\nconst localHuronPath = ! path.isAbsolute(program.huronConfig) ?\n path.join(cwd, program.huronConfig) :\n program.huronConfig;\nconst localConfig = requireExternal(localConfigPath);\nconst localHuron = requireExternal(localHuronPath);\n\n/**\n * Generate a mutant hybrid of the huron default webpack config and your local webpack config\n *\n * @function generateConfig\n * @param {object} config - local webpack config\n * @return {object} newConfig - updated data store\n */\nexport default function generateConfig() {\n let newConfig = localConfig;\n let newHuron = localHuron;\n\n // Execute config function, if provided\n if ('function' === typeof newConfig) {\n newConfig = newConfig(program.env);\n }\n\n // Execute huron config function, if provided\n if ('function' === typeof newHuron) {\n newHuron = newHuron(program.env);\n }\n\n // Merge huron defaults with user settings\n newHuron = Object.assign({}, defaultHuron, newHuron);\n // Use user huron config to modify webpack defaults\n defaultConfig = defaultWebpack(newHuron);\n\n // Set ouput options\n newConfig.output = Object.assign({}, defaultConfig.output, newConfig.output);\n newConfig.output.path = defaultConfig.output.path;\n newConfig.output.publicPath = defaultConfig.output.publicPath;\n\n // configure entries\n newConfig = configureEntries(newHuron, newConfig);\n\n // configure plugins\n newConfig = configurePlugins(newHuron, newConfig);\n\n // configure loaders\n newConfig = configureLoaders(newHuron, newConfig);\n\n // Add HTMLWebpackPlugin for each configured prototype\n newConfig = configurePrototypes(newHuron, newConfig);\n\n // Remove existing devServer settings\n delete newConfig.devServer;\n\n return {\n huron: newHuron,\n webpack: newConfig,\n };\n}\n\n/**\n * Configure and manage webpack entry points\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configureEntries(huron, config) {\n const entry = config.entry[huron.entry];\n const newConfig = config;\n\n newConfig.entry = {};\n if (! program.production) {\n newConfig.entry[huron.entry] = [\n `webpack-dev-server/client?http://localhost:${huron.port}`,\n 'webpack/hot/dev-server',\n path.join(cwd, huron.root, 'huron-assets/huron'),\n ].concat(entry);\n } else {\n newConfig.entry[huron.entry] = [\n path.join(cwd, huron.root, 'huron-assets/huron'),\n ].concat(entry);\n }\n\n return newConfig;\n}\n\n/**\n * Configure and manage webpack plugins\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configurePlugins(huron, config) {\n const newConfig = config;\n\n newConfig.plugins = config.plugins || [];\n\n if (! program.production) {\n if (newConfig.plugins && newConfig.plugins.length) {\n newConfig.plugins = newConfig.plugins.filter(\n (plugin) => 'HotModuleReplacementPlugin' !== plugin.constructor.name &&\n 'NamedModulesPlugin' !== plugin.constructor.name\n );\n }\n newConfig.plugins = newConfig.plugins\n .concat([\n new webpack.HotModuleReplacementPlugin(),\n new webpack.NamedModulesPlugin(),\n ]);\n }\n\n return newConfig;\n}\n\n/**\n * Configure and manage webpack loaders\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configureLoaders(huron, config) {\n // Manage loaders\n const templatesLoader = huron.templates.rule || {};\n const newConfig = config;\n\n // Make sure we're only using templates loader for files in huron root\n templatesLoader.include = [path.join(cwd, huron.root, huron.output)];\n\n // Normalize module and module.rules\n newConfig.module = newConfig.module || {};\n newConfig.module.rules = newConfig.module.rules ||\n newConfig.module.loaders ||\n [];\n\n // Add default loaders\n newConfig.module.rules = defaultConfig.module.rules\n .concat(\n newConfig.module.rules,\n templatesLoader\n );\n\n return newConfig;\n}\n\n/**\n * Create an HTML webpack plugin for each configured prototype\n *\n * @param {object} huron - huron configuration object\n * @param {object} config - webpack configuration object\n * @return {object} newConfig - updated data store\n */\nfunction configurePrototypes(huron, config) {\n const wrapperTemplate = fs.readFileSync(\n path.join(__dirname, '../../templates/prototype-template.hbs'),\n 'utf8'\n );\n\n const defaultHTMLPluginOptions = {\n title: 'Huron',\n window: huron.window,\n js: [],\n css: [],\n filename: 'index.html',\n template: path.join(\n cwd,\n huron.root,\n 'huron-assets/prototype-template.hbs'\n ),\n inject: false,\n chunks: [huron.entry],\n };\n const newConfig = config;\n\n // Write prototype template file for HTML webpack plugin\n fs.outputFileSync(\n path.join(cwd, huron.root, 'huron-assets/prototype-template.hbs'),\n wrapperTemplate\n );\n\n huron.prototypes.forEach((prototype) => {\n const newPrototype = prototype;\n let opts = {};\n\n // Merge configured settings with default settings\n if ('string' === typeof prototype) {\n opts = Object.assign({}, defaultHTMLPluginOptions, {\n title: prototype,\n filename: `${prototype}.html`,\n });\n } else if (\n 'object' === typeof prototype &&\n {}.hasOwnProperty.call(prototype, 'title')\n ) {\n // Create filename based on configured title if not provided\n if (! prototype.filename) {\n newPrototype.filename = `${prototype.title}.html`;\n }\n\n // Move css assets for this prototype,\n // reset css option with new file paths\n if (prototype.css) {\n newPrototype.css = moveAdditionalAssets(prototype.css, 'css', huron);\n }\n\n // Move js assets for this prototype,\n // reset js option with new file paths\n if (prototype.js) {\n newPrototype.js = moveAdditionalAssets(prototype.js, 'js', huron);\n }\n\n opts = Object.assign({}, defaultHTMLPluginOptions, newPrototype);\n }\n\n // Move global css assets,\n // reset css option with new file paths\n if (huron.css.length) {\n opts.css = opts.css.concat(\n moveAdditionalAssets(huron.css, 'css', huron)\n );\n }\n\n // Move global js assets,\n // reset js option with new file paths\n if (huron.js.length) {\n opts.js = opts.js.concat(\n moveAdditionalAssets(huron.js, 'js', huron)\n );\n }\n\n // Push a new plugin for each configured prototype\n if (Object.keys(opts).length) {\n newConfig.plugins.push(\n new HTMLWebpackPlugin(opts)\n );\n }\n });\n\n return newConfig;\n}\n\n/**\n * Move relative (and local) js and css assets provided in huron options\n *\n * @param {array|string} assets - array of assets or single asset\n * @param {string} subdir - subdirectory in huron root from which to load additional asset\n * @param {object} huron - huron configuration object\n * @return {array} assetResults - paths to js and css assets\n */\nfunction moveAdditionalAssets(assets, subdir = '', huron) {\n const currentAssets = [].concat(assets);\n const assetResults = [];\n\n currentAssets.forEach((asset) => {\n const assetInfo = path.parse(asset);\n const assetURL = url.parse(asset);\n const sourcePath = path.join(cwd, asset);\n const outputPath = path.resolve(cwd, huron.root, subdir, assetInfo.base);\n const loadPath = program.production ?\n path.join(subdir, assetInfo.base) :\n path.join('/', subdir, assetInfo.base); // Use absolute path in development\n let contents = false;\n\n if (\n ! path.isAbsolute(asset) &&\n ! assetURL.protocol\n ) {\n try {\n contents = fs.readFileSync(sourcePath);\n } catch (e) {\n console.warn(`could not read ${sourcePath}`);\n }\n\n if (contents) {\n fs.outputFileSync(outputPath, contents);\n assetResults.push(loadPath);\n }\n } else {\n assetResults.push(asset);\n }\n });\n\n return assetResults;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/generate-config.js","/** @module cli/html-handler */\nimport * as utils from './utils';\n\nconst path = require('path');\nconst fs = require('fs-extra');\n\n/**\n * Handle update of an HMTL template\n *\n * @function updateHTML\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updateHTML(filepath, section, store) {\n const file = path.parse(filepath);\n const content = fs.readFileSync(filepath, 'utf8');\n const newSection = section;\n\n if (content) {\n newSection.templatePath = utils.writeFile(\n section.referenceURI,\n 'template',\n filepath,\n content,\n store\n );\n newSection.templateContent = content;\n\n // Rewrite section data with template content\n newSection.sectionPath = utils.writeSectionData(store, newSection);\n\n return store\n .setIn(\n ['sections', 'sectionsByPath', section.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n console.log(`File ${file.base} could not be read`);\n return store;\n}\n\n/**\n * Handle removal of an HMTL template\n *\n * @function deleteHTML\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - contains KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deleteHTML(filepath, section, store) {\n const newSection = section;\n\n utils.removeFile(\n newSection.referenceURI,\n 'template',\n filepath,\n store\n );\n\n delete newSection.templatePath;\n\n return store\n .setIn(\n ['sections', 'sectionsByPath', section.kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n}\n\n/**\n * Handle update for a prototype file\n *\n * @function updatePrototype\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updatePrototype(filepath, store) {\n const file = path.parse(filepath);\n const content = fs.readFileSync(filepath, 'utf8');\n\n if (content) {\n const requirePath = utils.writeFile(\n file.name,\n 'prototype',\n filepath,\n content,\n store\n );\n\n return store.setIn(\n ['prototypes', file.name],\n requirePath\n );\n }\n\n console.log(`File ${file.base} could not be read`);\n return store;\n}\n\n/**\n * Handle removal of a prototype file\n *\n * @function deletePrototype\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deletePrototype(filepath, store) {\n const file = path.parse(filepath);\n const requirePath = utils.removeFile(\n file.name,\n 'prototype',\n filepath,\n store\n );\n\n return store.setIn(\n ['prototypes', file.name],\n requirePath\n );\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-html.js","/** @module cli/kss-handler */\n\nimport * as utils from './utils';\nimport { updateTemplate, deleteTemplate } from './handle-templates';\nimport { writeStore } from './require-templates';\n\nconst path = require('path');\nconst fs = require('fs-extra');\nconst parse = require('kss').parse;\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Handle update of a KSS section\n *\n * @function updateKSS\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function updateKSS(filepath, store) {\n const kssSource = fs.readFileSync(filepath, 'utf8');\n const huron = store.get('config');\n const oldSection = utils.getSection(filepath, false, store) || {};\n const file = path.parse(filepath);\n let newStore = store;\n\n if (kssSource) {\n const styleguide = parse(kssSource, huron.get('kssOptions'));\n\n if (styleguide.data.sections.length) {\n const section = utils.normalizeSectionData(\n styleguide.data.sections[0]\n );\n\n if (section.reference && section.referenceURI) {\n // Update or add section data\n newStore = updateSectionData(\n filepath,\n section,\n oldSection,\n newStore\n );\n\n // Remove old section data if reference URI has changed\n if (oldSection &&\n oldSection.referenceURI &&\n oldSection.referenceURI !== section.referenceURI\n ) {\n newStore = unsetSection(oldSection, file, newStore, false);\n }\n\n writeStore(newStore);\n console.log(\n chalk.green(\n `KSS source in ${filepath} changed or added`\n )\n );\n return newStore;\n }\n\n console.log(\n chalk.magenta(\n `KSS section in ${filepath} is missing a section reference`\n )\n );\n return newStore;\n }\n\n console.log(chalk.magenta(`No KSS found in ${filepath}`));\n return newStore;\n }\n\n if (oldSection) {\n newStore = deleteKSS(filepath, oldSection, newStore);\n }\n\n console.log(chalk.red(`${filepath} not found or empty`)); // eslint-disable-line no-console\n return newStore;\n}\n\n/**\n * Handle removal of a KSS section\n *\n * @function deleteKSS\n * @param {string} filepath - filepath of changed file (comes from gaze)\n * @param {object} section - KSS section data\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nexport function deleteKSS(filepath, section, store) {\n const file = path.parse(filepath);\n\n if (section.reference && section.referenceURI) {\n // Remove section data from memory store\n return unsetSection(section, file, store, true);\n }\n\n return store;\n}\n\n/**\n * Update the sections store with new data for a specific section\n *\n * @function updateSectionData\n * @param {object} section - contains updated section data\n * @param {string} kssPath - path to KSS section\n * @param {object} store - memory store\n * @return {object} updated data store\n */\nfunction updateSectionData(kssPath, section, oldSection, store) {\n const sectionFileInfo = path.parse(kssPath);\n const dataFilepath = path.join(\n sectionFileInfo.dir,\n `${sectionFileInfo.name}.json`\n );\n const isInline = null !== section.markup.match(/<\\/[^>]*>/);\n const newSort = sortSection(\n store.getIn(['sections', 'sorted']),\n section.reference,\n store.get('referenceDelimiter')\n );\n const newSection = Object.assign({}, oldSection, section);\n let newStore = store;\n\n // Required for reference from templates and data\n newSection.kssPath = kssPath;\n\n if (isInline) {\n // Set section value if inlineTempalte() returned a path\n newStore = updateInlineTemplate(\n kssPath,\n oldSection,\n newSection,\n newStore\n );\n } else {\n // Remove inline template, if it exists\n utils.removeFile(\n newSection.referenceURI,\n 'template',\n kssPath,\n store\n );\n // Update markup and data fields\n newStore = updateTemplateFields(\n sectionFileInfo,\n oldSection,\n newSection,\n newStore\n );\n }\n\n // Output section description\n newStore = updateDescription(\n kssPath,\n oldSection,\n newSection,\n newStore\n );\n\n // Output section data to a JSON file\n newSection.sectionPath = utils.writeSectionData(\n newStore,\n newSection,\n dataFilepath\n );\n\n // Update section sorting\n return newStore\n .setIn(\n ['sections', 'sorted'],\n newSort\n )\n .setIn(\n ['sections', 'sectionsByPath', kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n}\n\n/**\n * Handle detection and output of inline templates, which is markup written\n * in the KSS documentation itself as opposed to an external file\n *\n * @function updateInlineTemplate\n * @param {string} oldSection - previous iteration of KSS data, if updated\n * @param {object} section - KSS section data\n * @return {object} updated data store with new template path info\n */\nfunction updateInlineTemplate(filepath, oldSection, section, store) {\n const newSection = section;\n const newStore = store;\n\n // If we have inline markup\n if (fieldShouldOutput(oldSection, section, 'markup')) {\n newSection.templatePath = utils.writeFile(\n section.referenceURI,\n 'template',\n filepath,\n section.markup,\n store\n );\n newSection.templateContent = section.markup;\n\n return newStore\n .setIn(\n ['sections', 'sectionsByPath', filepath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle output of section description\n *\n * @function updateDescription\n * @param {string} oldSection - previous iteration of KSS data, if updated\n * @param {object} section - KSS section data\n * @return {object} updated data store with new descripton path info\n */\nfunction updateDescription(filepath, oldSection, section, store) {\n const newSection = section;\n const newStore = store;\n\n // If we don't have previous KSS or the KSS has been updated\n if (fieldShouldOutput(oldSection, section, 'description')) {\n // Write new description\n newSection.descriptionPath = utils.writeFile(\n section.referenceURI,\n 'description',\n filepath,\n section.description,\n store\n );\n\n return newStore\n .setIn(\n ['sections', 'sectionsByPath', filepath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', section.referenceURI],\n newSection\n );\n }\n\n return newStore;\n}\n\n/**\n * Handle Data and Markup fields\n *\n * @function updateTemplateFields\n * @param {string} file - File data for KSS file from path.parse()\n * @param {object} oldSection - outdated KSS data\n * @param {object} section - KSS section data\n * @param {object} store - memory store\n * @return {object} KSS section data with updated asset paths\n */\nfunction updateTemplateFields(file, oldSection, section, store) {\n const kssPath = path.format(file);\n const newSection = section;\n let filepath = '';\n let oldFilepath = '';\n let newStore = store;\n\n ['data', 'markup'].forEach((field) => {\n if (newSection[field]) {\n if (oldSection[field]) {\n oldFilepath = path.join(file.dir, oldSection[field]);\n newStore = deleteTemplate(\n oldFilepath,\n oldSection,\n newStore\n );\n }\n\n filepath = path.join(file.dir, newSection[field]);\n newStore = updateTemplate(\n filepath,\n newSection,\n newStore\n );\n } else {\n delete newSection[field];\n newStore = newStore\n .setIn(\n ['sections', 'sectionsByPath', kssPath],\n newSection\n )\n .setIn(\n ['sections', 'sectionsByURI', newSection.referenceURI],\n newSection\n );\n }\n });\n\n return newStore;\n}\n\n/**\n * Remove a section from the memory store\n *\n * @function unsetSection\n * @param {object} section - contains updated section data\n * @param {string} file - file object from path.parse()\n * @param {object} store - memory store\n * @param {bool} removed - has the file been removed or just the section information changed?\n * @return {object} updated data store with new descripton path info\n */\nfunction unsetSection(section, file, store, removed) {\n const sorted = store.getIn(['sections', 'sorted']);\n const kssPath = path.format(file);\n const dataFilepath = path.join(file.dir, `${file.name}.json`);\n const isInline = section.markup &&\n null !== section.markup.match(/<\\/[^>]*>/);\n const newSort = unsortSection(\n sorted,\n section.reference,\n store.get('referenceDelimiter')\n );\n let newStore = store;\n\n // Remove old section data\n utils.removeFile(\n section.referenceURI,\n 'section',\n dataFilepath,\n newStore\n );\n\n // Remove associated inline template\n if (isInline) {\n utils.removeFile(section.referenceURI, 'template', kssPath, newStore);\n }\n\n // Remove description template\n utils.removeFile(section.referenceURI, 'description', kssPath, newStore);\n\n // Remove data from sectionsByPath if file has been removed\n if (removed) {\n newStore = newStore.deleteIn(['sections', 'sectionsByPath', kssPath]);\n }\n\n return newStore\n .deleteIn(['sections', 'sectionsByURI', section.referenceURI])\n .setIn(['sections', 'sorted'], newSort);\n}\n\n/**\n * Sort sections and subsections\n *\n * @function sortSection\n * @param {object} sorted - currently sorted sections\n * @param {string} reference - reference URI of section to sort\n * @return {object} updated data store with new descripton path info\n */\nfunction sortSection(sorted, reference, delimiter) {\n const parts = reference.split(delimiter);\n const newSort = sorted[parts[0]] || {};\n const newSorted = sorted;\n\n if (1 < parts.length) {\n const newParts = parts.filter((part, idx) => 0 !== idx);\n newSorted[parts[0]] = sortSection(\n newSort,\n newParts.join(delimiter),\n delimiter\n );\n } else {\n newSorted[parts[0]] = newSort;\n }\n\n return newSorted;\n}\n\n/**\n * Remove a section from the sorted sections\n *\n * @function unsortSection\n * @param {object} sorted - currently sorted sections\n * @param {string} reference - reference URI of section to sort\n * @return {object} updated data store with new descripton path info\n */\nfunction unsortSection(sorted, reference, delimiter) {\n const parts = reference.split(delimiter);\n const subsections = Object.keys(sorted[parts[0]]);\n const newSorted = sorted;\n\n if (subsections.length) {\n if (1 < parts.length) {\n const newParts = parts.filter((part, idx) => 0 !== idx);\n newSorted[parts[0]] = unsortSection(\n newSorted[parts[0]],\n newParts.join(delimiter),\n delimiter\n );\n }\n } else {\n delete newSorted[parts[0]];\n }\n\n return newSorted;\n}\n\n/**\n * Compare a KSS field between old and new KSS data to see if we need to output\n * a new module for that field\n *\n * @function fieldShouldOutput\n * @param {object} oldSection - currently sorted sections\n * @param {object} newSection - reference URI of section to sort\n * @param {string} field - KSS field to check\n * @return {bool} output a new module for the KSS field\n */\nfunction fieldShouldOutput(oldSection, newSection, field) {\n return (oldSection &&\n (oldSection[field] !== newSection[field] ||\n oldSection.referenceURI !== newSection.referenceURI)\n ) ||\n ! oldSection;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/handle-kss.js","import { Map } from 'immutable';\nimport generateConfig from './generate-config';\n// Create initial data structure\n\n// Merge Huron default webpack config with user config\nconst config = generateConfig();\n\n// Make sure the kss option is represented as an array\nconfig.huron.kss = Array.isArray(config.huron.kss) ?\n config.huron.kss :\n [config.huron.kss];\n\n/* eslint-disable */\n/**\n * Initial structure for immutable data store\n *\n * @global\n */\nconst dataStructure = Map({\n types: [\n 'template',\n 'data',\n 'description',\n 'section',\n 'prototype',\n 'sections-template',\n ],\n config: Map(config.huron),\n sections: Map({\n sectionsByPath: Map({}),\n sectionsByURI: Map({}),\n sorted: {},\n }),\n templates: Map({}),\n prototypes: Map({}),\n sectionTemplatePath: '',\n referenceDelimiter: '.',\n});\n/* eslint-enable */\n\nexport { dataStructure, config };\n\n\n\n// WEBPACK FOOTER //\n// src/cli/huron-store.js","// Necessary to remove require statement from Webpack processing preserve it in output\n/* eslint-disable import/no-dynamic-require, global-require */\nexport default function requireExternal(requirePath) {\n return require(requirePath);\n}\n/* eslint-enable */\n\n\n\n// WEBPACK FOOTER //\n// src/cli/require-external.js","/** @module cli/webpack-server */\n\nimport program from './parse-args';\n\nconst webpack = require('webpack');\nconst WebpackDevServer = require('webpack-dev-server');\nconst chalk = require('chalk'); // Colorize terminal output\n\n/**\n * Spin up webpack-dev-server or, if production flag is set, run webpack a single time\n *\n * @function startWebpack\n * @param {object} config - webpack configuration, preprocessed by {@link module:cli/generate-config generateConfig}\n * @see {@link module:cli/generate-config generateConfig}\n */\nexport default function startWebpack(config) {\n const huron = config.huron;\n const webpackConfig = config.webpack;\n const compiler = webpack(webpackConfig);\n\n if (program.progress) {\n compiler.apply(\n new webpack.ProgressPlugin(\n (percentage, msg) => {\n console.log(`${(percentage * 100)}% `, msg);\n }\n )\n );\n }\n\n if (program.production) {\n compiler.run((err, stats) => {\n const info = stats.toJson();\n\n if (err) {\n console.log(err);\n }\n\n if (stats.hasErrors()) {\n console.error(\n chalk.red(\n 'Webpack encountered errors during compile: ',\n info.errors\n )\n );\n }\n\n if (stats.hasWarnings()) {\n console.error(\n chalk.yellow(\n 'Webpack encountered warnings during compile: ', info.warnings\n )\n );\n }\n });\n } else {\n const server = new WebpackDevServer(compiler, {\n hot: true,\n quiet: false,\n noInfo: false,\n stats: {\n colors: true,\n hash: false,\n version: false,\n assets: false,\n chunks: false,\n modules: false,\n reasons: false,\n children: false,\n source: false,\n },\n contentBase: huron.root,\n publicPath: `http://localhost:${huron.port}/${huron.root}`,\n });\n server.listen(\n huron.port,\n 'localhost',\n (err) => {\n if (err) {\n return console.log(err);\n }\n\n console.log(`Listening at http://localhost:${huron.port}/`);\n return true;\n }\n );\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/server.js","const path = require('path');\n\nmodule.exports = {\n css: [],\n entry: 'huron',\n js: [],\n kss: 'css/',\n kssExtension: '.css',\n kssOptions: {\n multiline: true,\n markdown: true,\n custom: ['data'],\n },\n output: 'partials',\n port: 8080,\n prototypes: ['index'],\n root: 'dist/',\n sectionTemplate: path.join(__dirname, '../../templates/section.hbs'),\n templates: {\n rule: {\n test: /\\.(hbs|handlebars)$/,\n use: 'handlebars-template-loader',\n },\n extension: '.hbs',\n },\n window: {},\n};\n\n\n\n// WEBPACK FOOTER //\n// src/default-config/huron.config.js","import program from '../cli/parse-args';\n\nconst webpack = require('webpack');\nconst path = require('path');\n\nmodule.exports = (huron) => {\n const cwd = process.cwd();\n\n return {\n entry: {},\n output: {\n path: path.join(cwd, huron.root),\n publicPath: program.production ? '' :\n `http://localhost:${huron.port}/${huron.root}`,\n filename: '[name].js',\n chunkFilename: '[name].chunk.min.js',\n },\n plugins: [\n new webpack.HotModuleReplacementPlugin(),\n new webpack.NamedModulesPlugin(),\n ],\n resolve: {\n modulesDirectories: [\n path.resolve(__dirname, '../src/js'),\n ],\n },\n resolveLoader: {\n modulesDirectories: [\n 'web_loaders',\n 'web_modules',\n 'node_loaders',\n 'node_modules',\n path.resolve(__dirname, '../node_modules'),\n ],\n },\n module: {\n rules: [\n {\n test: /\\.html$/,\n include: [path.join(cwd, huron.root, huron.output)],\n use: 'html-loader',\n },\n {\n test: /\\.(hbs|handlebars)$/,\n include: [path.join(cwd, huron.root, 'huron-assets')],\n use: {\n loader: 'handlebars-loader',\n options: {\n helperDirs: path.join(\n __dirname,\n '../../',\n 'templates/handlebars-helpers'\n ),\n },\n },\n },\n ],\n },\n };\n};\n\n\n\n// WEBPACK FOOTER //\n// src/default-config/webpack.config.js","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 18\n// module chunks = 0","module.exports = require(\"gaze\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"gaze\"\n// module id = 19\n// module chunks = 0","module.exports = require(\"html-webpack-plugin\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"html-webpack-plugin\"\n// module id = 20\n// module chunks = 0","module.exports = require(\"immutable\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"immutable\"\n// module id = 21\n// module chunks = 0","module.exports = require(\"kss\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kss\"\n// module id = 22\n// module chunks = 0","module.exports = require(\"url\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"url\"\n// module id = 23\n// module chunks = 0","module.exports = require(\"webpack-dev-server\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack-dev-server\"\n// module id = 24\n// module chunks = 0"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;A;;;;AChEA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC3CA;AAkBA;AAqCA;AAqCA;AAcA;AAkBA;AAyBA;AA4CA;AAyCA;AAyBA;AAyBA;AA1SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAGA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AAGA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;;AAFA;AAKA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;AC3TA;;;;;;;;;;;;ACgBA;AA0DA;AACA;AA1EA;AACA;AADA;AACA;;;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAUA;;;;;;;;;;;;ACnGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;;;;;;;;;AASA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;;;AAGA;;;AAGA;AACA;;;;;;;;;;;AAWA;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;AAwBA;;;;;;;;;;;;;;;;AA5CA;AACA;AA6DA;;;;;;;;;;;;;AAAA;AACA;AAcA;AACA;AACA;AAGA;AAHA;AAMA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAHA;AAMA;;;;;;;;;ACtIA;AACA;AAAA;AACA;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACxGA;AA2CA;AA+DA;AACA;AAnIA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;AADA;AACA;;;AACA;AAbA;AACA;AACA;AAYA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxBA;AACA;AA0BA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxCA;AACA;AA0CA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AArCA;AACA;AAuCA;AACA;;;;;;;;;;;;ACtJA;AACA;AA/BA;AACA;;;AAAA;AACA;;;;;AAHA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAKA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAZA;AAcA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC9RA;AA0CA;AA+BA;AA+BA;AACA;AAvHA;AACA;AADA;AACA;;;AACA;AACA;AAAA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AASA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AAMA;AAIA;;;;;;;;;;;;ACjHA;AAsEA;AACA;AAxFA;AACA;AADA;AACA;AAAA;AACA;AAAA;AACA;;;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAMA;AACA;AAIA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AAIA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAMA;AACA;AAMA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAKA;AACA;AAaA;AACA;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AASA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;AAUA;AACA;AAKA;;;;;;;;;;;;;;AC9aA;AACA;AAAA;AACA;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;AAKA;AACA;AAQA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AAlBA;AAoBA;AACA;AACA;AAAA;;;;;;;;;;;ACtCA;AAFA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACUA;AACA;AAdA;AACA;;;;;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AAhBA;AAkBA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;ACvFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AALA;AAOA;AAvBA;;;;;;;;;ACFA;AACA;;;;;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AALA;AAOA;AAIA;AACA;AADA;AAKA;AACA;AADA;AASA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AADA;AAFA;AAHA;AAPA;AA3BA;AAmDA;;;;;;AC3DA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/dist/web/huron.js b/dist/web/huron.js
index cb7304f..5ce0ab7 100644
--- a/dist/web/huron.js
+++ b/dist/web/huron.js
@@ -1,6 +1,14 @@
'use strict';
-const md5 = require('js-md5');
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var md5 = require('js-md5');
/* eslint-disable no-underscore-dangle */
// Accept the huron.js module for Huron development
@@ -13,9 +21,11 @@ if (module.hot) {
* into an element with attribute [huron-id] corresponding to the reference URI of the target KSS section,
* and [huron-type] corresponding with the required KSS field
*/
-class InsertNodes {
- constructor(modules, store) {
+var InsertNodes = function () {
+ function InsertNodes(modules, store) {
+ _classCallCheck(this, InsertNodes);
+
/** webpack module list in which keys are relative require paths and values are the module contents */
this._modules = modules;
/** array of module keys */
@@ -49,648 +59,750 @@ class InsertNodes {
* @param {object} meta - module metadata
* @return {string} rendered - the modified HTML module
*/
- static applyModifier(modifier, meta) {
- let rendered = false;
- let data = meta.data;
-
- if (data) {
- // If we have a modifier, use it, otherwise use the entire data set
- if (modifier && meta.data[modifier]) {
- data = Object.assign({}, meta.data[modifier], { modifier });
- }
- rendered = meta.render(data);
- } else {
- rendered = meta.render();
- }
- return rendered;
- }
+ _createClass(InsertNodes, [{
+ key: 'cycleModules',
- /**
- * Get markup from any type of module (html, json or template)
- *
- * @param {string} content - String corresponding to markup
- * @return {object} el.firstElementChild - HTML module
- */
- static convertToElement(content) {
- const el = document.createElement('div');
- el.innerHTML = content;
- return el.firstElementChild;
- }
+ /**
+ * Replace all template markers with the actual template markup.
+ *
+ * @param {string} context - The hash context for the module
+ * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs
+ */
+ value: function cycleModules() {
+ var _this = this;
- /**
- * Filter module object by module key or module type
- *
- * @param {object} filter - Filter for modules. Options:
- * @param {string} filter.property - Which property to filter ('key' or 'type')
- * @param {array} filter.values - Values for property
- * @param {bool} filter.include - Whether the values should be included or excluded (true = include, false = exclude)
- * @param {object} moduleMeta - Filter for modules. Fields explained in the filterModules() function docs
- * @return {bool} match - determine if modules need to be filtered
- */
- static filterModules(filter, moduleMeta) {
- let match = true;
+ var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+ var filter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
- // Check if we should filter out any modules
- if ('object' === typeof filter && {}.hasOwnProperty.call(filter, 'property') && {}.hasOwnProperty.call(filter, 'values') && {}.hasOwnProperty.call(filter, 'include')) {
- match = filter.values.filter(value => moduleMeta[filter.property] === value);
- return Boolean(match.length) === filter.include;
- }
+ var moduleList = {};
+ var elementList = context;
- console.log(` // eslint-disable-line no-console
- filter ${filter} is not in a valid format.
- module filters must include 'property', 'values', and 'include' properties
- `);
+ // We're replacing top-level elements
+ if (!elementList) {
+ this.regenCache();
- return match;
- }
+ // Find all top-level huron placeholders
+ elementList = [].concat(_toConsumableArray(document.querySelectorAll('[data-huron-id][data-huron-type]')));
+ }
- /**
- * Generate a hash string from a module key
- *
- * @param {string} key - module key (require path) to convert into a hash
- * @return {string} key - generated MD5 Hash
- */
- static generateModuleHash(key) {
- return md5(key);
- }
+ moduleList = this.getModuleListFromTags(elementList);
- /**
- * Retrieve a data attribute from a tag using one of two methods
- *
- * @param {HTMLElement} tag - DOM node on which to check for a data attribute
- * @param {string} attr - attribute to check for
- * @returns {string} data - contents of data attribute
- */
- static getDataAttribute(tag, attr) {
- let data = false;
+ // Loop through modules array
+ Object.keys(moduleList).forEach(function (key) {
+ var module = _this._modules[key];
+ var replaceElements = moduleList[key];
- // Check if element has dataset and, if so, use it
- if (tag.dataset) {
- data = tag.dataset[attr];
+ _this.loadModule(key, module, replaceElements, true, filter);
+ });
}
- // Fallback to getAttribute for ugly old Safari
- if (!data && tag.getAttribute) {
- data = tag.getAttribute(`data-${attr}`);
+ /**
+ * Helper for reloading sections only
+ */
+
+ }, {
+ key: 'cycleSections',
+ value: function cycleSections() {
+ this.cycleModules(false, {
+ property: 'type',
+ values: ['section'],
+ include: true
+ });
}
- return data;
- }
+ /**
+ * Reload styleguide sections and menu helpers
+ */
+
+ }, {
+ key: 'cycleStyleguide',
+ value: function cycleStyleguide() {
+ var sectionsQuery = document.querySelector('[huron-sections]');
+ var menuQuery = document.querySelector('[huron-menu]');
+
+ // Sections
+ if (sectionsQuery) {
+ sectionsQuery.innerHTML = '';
+ this.outputSections(null, sectionsQuery);
+ this.cycleSections();
+ }
- /**
- * Check if this tag is a styleguide helper
- *
- * @param {object} tag - tag to check
- * @param {object} meta - module metadata
- * @return {bool}
- */
- static isSectionHelper(tag, meta) {
- if ('prototype' === meta.type) {
- return tag.hasAttribute('huron-sections') || tag.hasAttribute('huron-menu');
- }
+ // Menu
+ if (menuQuery) {
+ menuQuery.innerHTML = '';
- return false;
- }
+ if (null === document.querySelector('.section-menu__expand')) {
+ var menuTrigger = document.createElement('button');
- /**
- * Replace all template markers with the actual template markup.
- *
- * @param {string} context - The hash context for the module
- * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs
- */
- cycleModules(context = false, filter = false) {
- let moduleList = {};
- let elementList = context;
+ menuTrigger.classList.add('section-menu__expand');
+ menuTrigger.innerHTML = 'Sections Menu';
+ document.body.insertBefore(menuQuery.appendChild(menuTrigger), document.body.childNodes[0]);
- // We're replacing top-level elements
- if (!elementList) {
- this.regenCache();
+ // Add menu trigger handler
+ menuTrigger.addEventListener('click', function () {
+ document.body.classList.toggle('section-menu-open');
+ });
+ }
- // Find all top-level huron placeholders
- elementList = [...document.querySelectorAll('[data-huron-id][data-huron-type]')];
+ // Create menu
+ this.outputMenu(null, menuQuery);
+ }
}
- moduleList = this.getModuleListFromTags(elementList);
+ /**
+ * Get module metadata from a module require path
+ *
+ * @param {string} key - Module require path
+ * @return {object} containing module id, module type, key and the module contents
+ */
+
+ }, {
+ key: 'getMetaFromPath',
+ value: function getMetaFromPath(key, module) {
+ var _this2 = this;
+
+ var sections = this._sections.sectionsByPath;
+ var templateTypes = this._types.filter(function (type) {
+ return 'prototype' !== type;
+ });
+ var id = false;
+ var type = false;
+
+ /* eslint-disable space-unary-ops */
+ if (-1 !== key.indexOf('./prototypes')) {
+ /* eslint-enable space-unary-ops */
+ var prototype = Object.keys(this._prototypes).filter(function (name) {
+ return _this2._prototypes[name] === key;
+ });
- // Loop through modules array
- Object.keys(moduleList).forEach(key => {
- const module = this._modules[key];
- const replaceElements = moduleList[key];
+ if (prototype.length) {
+ id = prototype[0];
+ type = 'prototype';
+ }
+ } else if (key === this._sectionTemplatePath) {
+ id = 'sections-template';
+ type = 'sections-template';
+ } else {
+ var testTypes = [];
+ var testSections = Object.keys(sections).filter(function (section) {
+ var tempTypes = templateTypes.filter(function (currentType) {
+ return sections[section][currentType + 'Path'] === key;
+ });
- this.loadModule(key, module, replaceElements, true, filter);
- });
- }
+ if (tempTypes.length) {
+ testTypes = tempTypes;
+ return true;
+ }
- /**
- * Helper for reloading sections only
- */
- cycleSections() {
- this.cycleModules(false, {
- property: 'type',
- values: ['section'],
- include: true
- });
- }
+ return false;
+ });
- /**
- * Reload styleguide sections and menu helpers
- */
- cycleStyleguide() {
- const sectionsQuery = document.querySelector('[huron-sections]');
- const menuQuery = document.querySelector('[huron-menu]');
-
- // Sections
- if (sectionsQuery) {
- sectionsQuery.innerHTML = '';
- this.outputSections(null, sectionsQuery);
- this.cycleSections();
- }
+ if (testSections && testSections.length && testTypes && testTypes.length) {
+ id = sections[testSections[0]].referenceURI;
+ type = testTypes[0];
+ }
+ }
- // Menu
- if (menuQuery) {
- menuQuery.innerHTML = '';
+ if (id && type) {
+ var hashKey = 'data' === type ? this._templates[key] : key;
+ var renderData = this.getModuleRender(type, key, module);
+ var hash = InsertNodes.generateModuleHash(hashKey);
- if (null === document.querySelector('.section-menu__expand')) {
- const menuTrigger = document.createElement('button');
+ if (renderData) {
+ return Object.assign({ id: id, type: type, key: key, hash: hash, module: module }, renderData);
+ }
+ }
- menuTrigger.classList.add('section-menu__expand');
- menuTrigger.innerHTML = 'Sections Menu';
- document.body.insertBefore(menuQuery.appendChild(menuTrigger), document.body.childNodes[0]);
+ console.warn( // eslint-disable-line no-console
+ 'Module \'' + key + '\' does not exist on the page\n or is no longer in use');
+ return false;
+ }
- // Add menu trigger handler
- menuTrigger.addEventListener('click', () => {
- document.body.classList.toggle('section-menu-open');
- });
+ /**
+ * Check if a tag is a huron placeholder and, if so,
+ * return its associated module key
+ *
+ * @param {object} tag - tag to check
+ * @return {bool} associated module key
+ */
+
+ }, {
+ key: 'getModuleKeyFromTag',
+ value: function getModuleKeyFromTag(tag) {
+ // Safari/webkit has some trouble parsing dataset in certain cases.
+ // This is a fallback method of accessing the same data.
+ var type = InsertNodes.getDataAttribute(tag, 'huron-type');
+ var id = InsertNodes.getDataAttribute(tag, 'huron-id');
+ var section = this._sections.sectionsByURI[id];
+
+ if (id && type) {
+ if (section) {
+ return section[type + 'Path'];
+ } else if ('prototype' === type) {
+ return this._prototypes[id];
+ }
}
- // Create menu
- this.outputMenu(null, menuQuery);
+ return false;
}
- }
- /**
- * Get module metadata from a module require path
- *
- * @param {string} key - Module require path
- * @return {object} containing module id, module type, key and the module contents
- */
- getMetaFromPath(key, module) {
- const sections = this._sections.sectionsByPath;
- const templateTypes = this._types.filter(type => 'prototype' !== type);
- let id = false;
- let type = false;
-
- /* eslint-disable space-unary-ops */
- if (-1 !== key.indexOf('./prototypes')) {
- /* eslint-enable space-unary-ops */
- const prototype = Object.keys(this._prototypes).filter(name => this._prototypes[name] === key);
-
- if (prototype.length) {
- id = prototype[0];
- type = 'prototype';
- }
- } else if (key === this._sectionTemplatePath) {
- id = 'sections-template';
- type = 'sections-template';
- } else {
- let testTypes = [];
- const testSections = Object.keys(sections).filter(section => {
- const tempTypes = templateTypes.filter(currentType => sections[section][`${currentType}Path`] === key);
-
- if (tempTypes.length) {
- testTypes = tempTypes;
- return true;
- }
+ /**
+ * Check if an array of elements contains a Huron placeholder
+ *
+ * @param {array} tags - array of DOM nodes
+ * @param {bool} recurse - should we recurse this function with a new array
+ * @return {object} moduleList - Huron placeholder DOM node
+ */
- return false;
- });
+ }, {
+ key: 'getModuleListFromTags',
+ value: function getModuleListFromTags(elements) {
+ var _this3 = this;
+
+ var recurse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- if (testSections && testSections.length && testTypes && testTypes.length) {
- id = sections[testSections[0]].referenceURI;
- type = testTypes[0];
+ var moduleList = {};
+ var newList = {};
+
+ if (elements && elements.length) {
+ elements.forEach(function (element) {
+ var moduleKey = _this3.getModuleKeyFromTag(element);
+
+ if (moduleKey) {
+ if (!moduleList[moduleKey]) {
+ moduleList[moduleKey] = [];
+ }
+ moduleList[moduleKey].push(element);
+ } else if (recurse) {
+ newList = _this3.getModuleListFromTags([].concat(_toConsumableArray(element.querySelectorAll('[data-huron-id][data-huron-type]'))), false);
+
+ Object.keys(newList).forEach(function (key) {
+ moduleList[key] = moduleList[key] ? moduleList[key].concat(newList[key]) : newList[key];
+ });
+ }
+ });
}
+
+ return moduleList;
}
- if (id && type) {
- const hashKey = 'data' === type ? this._templates[key] : key;
- const renderData = this.getModuleRender(type, key, module);
- const hash = InsertNodes.generateModuleHash(hashKey);
+ /**
+ * Transform every module into a predictable object
+ *
+ * @param {object} type - Module metadata
+ * @param {mixed} module - Module contents
+ * @return {object} containing render function, render data and module id
+ */
+
+ }, {
+ key: 'getModuleRender',
+ value: function getModuleRender(type, key, module) {
+ var render = false;
+ var data = false;
+
+ if ('template' === type && 'function' === typeof module) {
+ // It's a render function for a template
+ render = module;
+ data = this._modules[this._templates[key]];
+ } else if ('sections-template' === type && 'function' === typeof module) {
+ // It's a kss section template
+ render = module;
+ } else if ('section' === type && 'object' === (typeof module === 'undefined' ? 'undefined' : _typeof(module))) {
+ // It's section data
+ render = this._modules[this._sectionTemplatePath];
+ data = module;
+ } else if (('template' === type || 'description' === type || 'prototype' === type) && 'string' === typeof module) {
+ // it's straight HTML
+ render = function render() {
+ return module;
+ };
+ } else if ('data' === type && 'object' === (typeof module === 'undefined' ? 'undefined' : _typeof(module))) {
+ // It's a data file (.json)
+ render = this._modules[this._templates[key]];
+ data = module;
+ }
- if (renderData) {
- return Object.assign({ id, type, key, hash, module }, renderData);
+ // Only need render, as data will be left empty for static HTML
+ if (render) {
+ return { render: render, data: data };
}
+
+ return false;
}
- console.warn( // eslint-disable-line no-console
- `Module '${key}' does not exist on the page
- or is no longer in use`);
- return false;
- }
+ /**
+ * Replace all sections. For hot reloading use when the section template has changed.
+ *
+ * @param {object} replaceElements - The context (e.g. document) that you will query for the template ID to replace
+ * @param {string} key - Module require path
+ * @param {mixed} module - Module contents
+ * @param {bool} cached - Whether or not to use cached values for module replacement
+ * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs
+ */
+
+ }, {
+ key: 'loadModule',
+ value: function loadModule(key, module, replaceElements) {
+ var cached = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
+ var filter = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+
+ var shouldLoad = true;
+ var moduleMeta = false;
+
+ // Check if we should load from internal module metadata cache
+ if (cached) {
+ moduleMeta = this.meta[key];
+ } else {
+ moduleMeta = this.meta[key] = this.getMetaFromPath(key, module);
+ }
- /**
- * Check if a tag is a huron placeholder and, if so,
- * return its associated module key
- *
- * @param {object} tag - tag to check
- * @return {bool} associated module key
- */
- getModuleKeyFromTag(tag) {
- // Safari/webkit has some trouble parsing dataset in certain cases.
- // This is a fallback method of accessing the same data.
- const type = InsertNodes.getDataAttribute(tag, 'huron-type');
- const id = InsertNodes.getDataAttribute(tag, 'huron-id');
- const section = this._sections.sectionsByURI[id];
-
- if (id && type) {
- if (section) {
- return section[`${type}Path`];
- } else if ('prototype' === type) {
- return this._prototypes[id];
+ if (moduleMeta) {
+ if (filter) {
+ shouldLoad = InsertNodes.filterModules(filter, moduleMeta);
+ }
+
+ if (shouldLoad) {
+ this.replaceTemplate(moduleMeta, replaceElements);
+ }
}
}
- return false;
- }
+ /*
+ * Helper function for inserting styleguide sections.
+ *
+ * Recurses over sorted styleguide sections and inserts a
to be used as a menu for each section
+ */
- /**
- * Check if an array of elements contains a Huron placeholder
- *
- * @param {array} tags - array of DOM nodes
- * @param {bool} recurse - should we recurse this function with a new array
- * @return {object} moduleList - Huron placeholder DOM node
- */
- getModuleListFromTags(elements, recurse = true) {
- const moduleList = {};
- let newList = {};
+ }, {
+ key: 'outputMenu',
+ value: function outputMenu(parent, el) {
+ var _this4 = this;
- if (elements && elements.length) {
- elements.forEach(element => {
- const moduleKey = this.getModuleKeyFromTag(element);
+ var sections = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._sections.sorted;
- if (moduleKey) {
- if (!moduleList[moduleKey]) {
- moduleList[moduleKey] = [];
+ var templateId = null;
+ var newEl = el;
+
+ Object.keys(sections).forEach(function (section) {
+ var hasSubmenu = Object.keys(sections[section]).length;
+ var menuTarget = void 0;
+ var nextMenu = void 0;
+
+ if (parent) {
+ templateId = parent + '-' + section;
+ } else {
+ templateId = section;
+ }
+
+ if (newEl) {
+ var title = _this4._sections.sectionsByURI[templateId] ? _this4._sections.sectionsByURI[templateId].header : templateId;
+ var sectionMenu = document.createElement('ul');
+ var menuItem = document.createElement('li');
+ var link = '' + title + '';
+
+ sectionMenu.classList.add('section-menu');
+ menuItem.classList.add('section-menu__item');
+ menuItem.innerHTML = link;
+
+ // Check if this is a UL and, if not, create one
+ if ('UL' !== newEl.tagName) {
+ menuTarget = sectionMenu.cloneNode();
+ newEl.appendChild(menuTarget);
+ newEl = menuTarget;
}
- moduleList[moduleKey].push(element);
- } else if (recurse) {
- newList = this.getModuleListFromTags([...element.querySelectorAll('[data-huron-id][data-huron-type]')], false);
- Object.keys(newList).forEach(key => {
- moduleList[key] = moduleList[key] ? moduleList[key].concat(newList[key]) : newList[key];
- });
+ // Has subsections
+ if (hasSubmenu) {
+ nextMenu = sectionMenu.cloneNode();
+ nextMenu.classList.add('section-menu--submenu');
+ menuItem.classList.add('section-menu__item--has-submenu');
+ menuItem.appendChild(nextMenu);
+ }
+
+ newEl.appendChild(menuItem);
+
+ if (hasSubmenu) {
+ _this4.outputMenu(templateId, nextMenu, sections[section]);
+ }
}
});
}
- return moduleList;
- }
+ /**
+ * Helper function for inserting styleguide sections.
+ *
+ * Recurses over sorted styleguide sections and inserts a tag with [huron-id] equal to the section template name.
+ */
- /**
- * Transform every module into a predictable object
- *
- * @param {object} type - Module metadata
- * @param {mixed} module - Module contents
- * @return {object} containing render function, render data and module id
- */
- getModuleRender(type, key, module) {
- let render = false;
- let data = false;
-
- if ('template' === type && 'function' === typeof module) {
- // It's a render function for a template
- render = module;
- data = this._modules[this._templates[key]];
- } else if ('sections-template' === type && 'function' === typeof module) {
- // It's a kss section template
- render = module;
- } else if ('section' === type && 'object' === typeof module) {
- // It's section data
- render = this._modules[this._sectionTemplatePath];
- data = module;
- } else if (('template' === type || 'description' === type || 'prototype' === type) && 'string' === typeof module) {
- // it's straight HTML
- render = () => module;
- } else if ('data' === type && 'object' === typeof module) {
- // It's a data file (.json)
- render = this._modules[this._templates[key]];
- data = module;
- }
+ }, {
+ key: 'outputSections',
+ value: function outputSections(parent, el) {
+ var _this5 = this;
+
+ var sections = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._sections.sorted;
- // Only need render, as data will be left empty for static HTML
- if (render) {
- return { render, data };
+ var templateId = null;
+ var placeholder = null;
+
+ Object.keys(sections).forEach(function (section) {
+ var istopLevel = false;
+ var topLevelWrapper = null;
+ var topLevelSection = null;
+ var insertionEl = el;
+
+ // Generate section ID and check if it is top-level
+ if (parent) {
+ templateId = parent + '-' + section;
+ } else {
+ templateId = section;
+ istopLevel = true;
+ }
+
+ if (el) {
+ // Generate huron placeholder for this section
+ placeholder = document.createElement('div');
+ placeholder.dataset.huronId = templateId;
+ placeholder.dataset.huronType = 'section';
+
+ if (istopLevel) {
+ // Generate wrapper to contain top-level section and all subsections underneath it
+ topLevelWrapper = document.createElement('div');
+ topLevelWrapper.classList.add('section--top-level__wrapper');
+
+ // Generate wrapper for top-level section
+ topLevelSection = document.createElement('div');
+ topLevelSection.classList.add('section', 'section--top-level');
+
+ // Append wrappers to huron-sections element
+ topLevelSection.appendChild(placeholder);
+ topLevelWrapper.appendChild(topLevelSection);
+ el.appendChild(topLevelWrapper);
+ insertionEl = topLevelWrapper;
+ } else {
+ // If this is not top-level, append placeholder
+ el.appendChild(placeholder);
+ }
+ }
+
+ // Recursively call this function to insert other sections
+ if (Object.keys(sections[section]).length && placeholder) {
+ _this5.outputSections(templateId, insertionEl, sections[section]);
+ }
+ });
}
- return false;
- }
+ /**
+ * Regenerate module meta cache
+ */
- /**
- * Replace all sections. For hot reloading use when the section template has changed.
- *
- * @param {object} replaceElements - The context (e.g. document) that you will query for the template ID to replace
- * @param {string} key - Module require path
- * @param {mixed} module - Module contents
- * @param {bool} cached - Whether or not to use cached values for module replacement
- * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs
- */
- loadModule(key, module, replaceElements, cached = false, filter = false) {
- let shouldLoad = true;
- let moduleMeta = false;
-
- // Check if we should load from internal module metadata cache
- if (cached) {
- moduleMeta = this.meta[key];
- } else {
- moduleMeta = this.meta[key] = this.getMetaFromPath(key, module);
+ }, {
+ key: 'regenCache',
+ value: function regenCache() {
+ var _this6 = this;
+
+ Object.keys(this._modules).forEach(function (moduleKey) {
+ _this6.meta[moduleKey] = _this6.getMetaFromPath(moduleKey, _this6._modules[moduleKey]);
+ });
}
- if (moduleMeta) {
- if (filter) {
- shouldLoad = InsertNodes.filterModules(filter, moduleMeta);
- }
+ /**
+ * Recursively remove old tags
+ *
+ * @param {string} hash - hash of module for which we need to remove old tags
+ * @param {object} tag - tag to start our search with
+ * (usually the tag immediately preceding the current placeholder)
+ */
+
+ }, {
+ key: 'removeOldTags',
+ value: function removeOldTags(hash, tag) {
+ if (tag) {
+ var parentHash = InsertNodes.getDataAttribute(tag, 'parent-hash');
+ var selfHash = InsertNodes.getDataAttribute(tag, 'self-hash');
+
+ if (parentHash === hash && selfHash !== hash) {
+ // This is a child of the current module,
+ // so remove it and its children (if applicable)
+ var childrenHash = selfHash;
+ var nextTag = tag.previousSibling;
+
+ if (childrenHash) {
+ this.removeOldTags(childrenHash, nextTag);
+ // Reset nextTag if we removed a child
+ nextTag = tag.previousSibling;
+ }
- if (shouldLoad) {
- this.replaceTemplate(moduleMeta, replaceElements);
+ tag.parentNode.removeChild(tag);
+ this.removeOldTags(hash, nextTag);
+ }
}
}
- }
- /*
- * Helper function for inserting styleguide sections.
- *
- * Recurses over sorted styleguide sections and inserts a
to be used as a menu for each section
- */
- outputMenu(parent, el, sections = this._sections.sorted) {
- let templateId = null;
- let newEl = el;
+ /**
+ * Replace a single template marker with template content.
+ *
+ * @param {object} replaceElements - Array of elements to check for Huron placeholders
+ * @param {object} meta - Module metadata
+ */
+
+ }, {
+ key: 'replaceTemplate',
+ value: function replaceTemplate(meta, replaceElements) {
+ var _this7 = this;
+
+ var type = this.validateType(meta.type);
+ var tags = [];
+ var replace = replaceElements;
+ var hasStyleguideHelpers = false;
+
+ if (!replace) {
+ replace = document.querySelectorAll('[data-huron-id][data-huron-type]');
+ }
- Object.keys(sections).forEach(section => {
- const hasSubmenu = Object.keys(sections[section]).length;
- let menuTarget;
- let nextMenu;
+ if (type) {
+ replace.forEach(function (tag) {
+ var tagType = InsertNodes.getDataAttribute(tag, 'huron-type');
+ var tagId = InsertNodes.getDataAttribute(tag, 'huron-id');
- if (parent) {
- templateId = `${parent}-${section}`;
- } else {
- templateId = section;
- }
+ if (tagId === meta.id && tagType === type) {
+ tags.push(tag);
+ }
+ });
- if (newEl) {
- const title = this._sections.sectionsByURI[templateId] ? this._sections.sectionsByURI[templateId].header : templateId;
- const sectionMenu = document.createElement('ul');
- const menuItem = document.createElement('li');
- const link = `${title}`;
-
- sectionMenu.classList.add('section-menu');
- menuItem.classList.add('section-menu__item');
- menuItem.innerHTML = link;
-
- // Check if this is a UL and, if not, create one
- if ('UL' !== newEl.tagName) {
- menuTarget = sectionMenu.cloneNode();
- newEl.appendChild(menuTarget);
- newEl = menuTarget;
- }
+ if (tags && tags.length && meta.render) {
+ tags.forEach(function (currentTag) {
+ var modifiedPlaceholder = currentTag;
+ var modifier = InsertNodes.getDataAttribute(modifiedPlaceholder, 'huron-modifier');
+ var parent = modifiedPlaceholder.parentNode;
+ var rendered = InsertNodes.applyModifier(modifier, meta);
+ var renderedTemplate = InsertNodes.convertToElement(rendered).querySelector('template');
+ var renderedContents = null;
- // Has subsections
- if (hasSubmenu) {
- nextMenu = sectionMenu.cloneNode();
- nextMenu.classList.add('section-menu--submenu');
- menuItem.classList.add('section-menu__item--has-submenu');
- menuItem.appendChild(nextMenu);
- }
+ // Remove existing module tags
+ _this7.removeOldTags(meta.hash, modifiedPlaceholder.previousSibling);
- newEl.appendChild(menuItem);
+ // Get the contents of the rendered template
+ renderedContents = [].concat(_toConsumableArray(renderedTemplate.content.children));
- if (hasSubmenu) {
- this.outputMenu(templateId, nextMenu, sections[section]);
- }
- }
- });
- }
+ // Insert each tag of the template contents before placeholder
+ renderedContents.forEach(function (element) {
+ var newEl = element;
- /**
- * Helper function for inserting styleguide sections.
- *
- * Recurses over sorted styleguide sections and inserts a tag with [huron-id] equal to the section template name.
- */
- outputSections(parent, el, sections = this._sections.sorted) {
- let templateId = null;
- let placeholder = null;
-
- Object.keys(sections).forEach(section => {
- let istopLevel = false;
- let topLevelWrapper = null;
- let topLevelSection = null;
- let insertionEl = el;
-
- // Generate section ID and check if it is top-level
- if (parent) {
- templateId = `${parent}-${section}`;
+ if (1 === newEl.nodeType) {
+ newEl.dataset.parentHash = meta.hash;
+ hasStyleguideHelpers = !hasStyleguideHelpers ? InsertNodes.isSectionHelper(newEl, meta) : hasStyleguideHelpers;
+
+ parent.insertBefore(newEl, modifiedPlaceholder);
+ }
+ });
+
+ // Add module hash to this placeholder
+ modifiedPlaceholder.dataset.selfHash = meta.hash;
+
+ // Hide the placeholder
+ modifiedPlaceholder.style.display = 'none';
+
+ // Recursively load modules, excluding the current one
+ _this7.cycleModules(renderedContents, {
+ property: 'key',
+ values: [meta.key, _this7._sectionTemplatePath],
+ include: false
+ });
+
+ if (hasStyleguideHelpers) {
+ _this7.cycleStyleguide();
+ }
+ });
+ }
} else {
- templateId = section;
- istopLevel = true;
+ console.warn( // eslint-disable-line no-console
+ 'Could not render module\n section: ' + meta.id + '\n type: ' + meta.type);
}
+ }
- if (el) {
- // Generate huron placeholder for this section
- placeholder = document.createElement('div');
- placeholder.dataset.huronId = templateId;
- placeholder.dataset.huronType = 'section';
-
- if (istopLevel) {
- // Generate wrapper to contain top-level section and all subsections underneath it
- topLevelWrapper = document.createElement('div');
- topLevelWrapper.classList.add('section--top-level__wrapper');
-
- // Generate wrapper for top-level section
- topLevelSection = document.createElement('div');
- topLevelSection.classList.add('section', 'section--top-level');
-
- // Append wrappers to huron-sections element
- topLevelSection.appendChild(placeholder);
- topLevelWrapper.appendChild(topLevelSection);
- el.appendChild(topLevelWrapper);
- insertionEl = topLevelWrapper;
- } else {
- // If this is not top-level, append placeholder
- el.appendChild(placeholder);
- }
+ /**
+ * Verify specified element is using an acceptable huron type
+ *
+ * @param {string} type - type of partial (template, data, description, section or prototype )
+ * @return {string} type - huron type or 'template' if invalid
+ */
+
+ }, {
+ key: 'validateType',
+ value: function validateType(type) {
+ if ('data' === type) {
+ return 'template';
}
- // Recursively call this function to insert other sections
- if (Object.keys(sections[section]).length && placeholder) {
- this.outputSections(templateId, insertionEl, sections[section]);
+ if (!this._types.includes(type)) {
+ return false;
}
- });
- }
- /**
- * Regenerate module meta cache
- */
- regenCache() {
- Object.keys(this._modules).forEach(moduleKey => {
- this.meta[moduleKey] = this.getMetaFromPath(moduleKey, this._modules[moduleKey]);
- });
- }
+ return type;
+ }
- /**
- * Recursively remove old tags
- *
- * @param {string} hash - hash of module for which we need to remove old tags
- * @param {object} tag - tag to start our search with
- * (usually the tag immediately preceding the current placeholder)
- */
- removeOldTags(hash, tag) {
- if (tag) {
- const parentHash = InsertNodes.getDataAttribute(tag, 'parent-hash');
- const selfHash = InsertNodes.getDataAttribute(tag, 'self-hash');
-
- if (parentHash === hash && selfHash !== hash) {
- // This is a child of the current module,
- // so remove it and its children (if applicable)
- const childrenHash = selfHash;
- let nextTag = tag.previousSibling;
-
- if (childrenHash) {
- this.removeOldTags(childrenHash, nextTag);
- // Reset nextTag if we removed a child
- nextTag = tag.previousSibling;
- }
+ /*
+ * Set new modules object
+ */
- tag.parentNode.removeChild(tag);
- this.removeOldTags(hash, nextTag);
- }
+ }, {
+ key: 'modules',
+ set: function set(modules) {
+ this._modules = modules;
+ this._moduleIds = Object.keys(modules);
}
- }
- /**
- * Replace a single template marker with template content.
- *
- * @param {object} replaceElements - Array of elements to check for Huron placeholders
- * @param {object} meta - Module metadata
- */
- replaceTemplate(meta, replaceElements) {
- const type = this.validateType(meta.type);
- const tags = [];
- let replace = replaceElements;
- let hasStyleguideHelpers = false;
-
- if (!replace) {
- replace = document.querySelectorAll('[data-huron-id][data-huron-type]');
+ /*
+ * Set store
+ */
+
+ }, {
+ key: 'store',
+ set: function set(store) {
+ this._store = store;
+ this._config = store.config;
+ this._sections = store.sections;
+ this._templates = store.templates;
+ this._prototypes = store.prototypes;
+ this._types = store.types;
+ this._sectionTemplatePath = store.sectionTemplatePath;
}
-
- if (type) {
- replace.forEach(tag => {
- const tagType = InsertNodes.getDataAttribute(tag, 'huron-type');
- const tagId = InsertNodes.getDataAttribute(tag, 'huron-id');
-
- if (tagId === meta.id && tagType === type) {
- tags.push(tag);
+ }], [{
+ key: 'applyModifier',
+ value: function applyModifier(modifier, meta) {
+ var rendered = false;
+ var data = meta.data;
+
+ if (data) {
+ // If we have a modifier, use it, otherwise use the entire data set
+ if (modifier && meta.data[modifier]) {
+ data = Object.assign({}, meta.data[modifier], { modifier: modifier });
}
- });
- if (tags && tags.length && meta.render) {
- tags.forEach(currentTag => {
- const modifiedPlaceholder = currentTag;
- const modifier = InsertNodes.getDataAttribute(modifiedPlaceholder, 'huron-modifier');
- const parent = modifiedPlaceholder.parentNode;
- const rendered = InsertNodes.applyModifier(modifier, meta);
- const renderedTemplate = InsertNodes.convertToElement(rendered).querySelector('template');
- let renderedContents = null;
+ rendered = meta.render(data);
+ } else {
+ rendered = meta.render();
+ }
- // Remove existing module tags
- this.removeOldTags(meta.hash, modifiedPlaceholder.previousSibling);
+ return rendered;
+ }
- // Get the contents of the rendered template
- renderedContents = [...renderedTemplate.content.children];
+ /**
+ * Get markup from any type of module (html, json or template)
+ *
+ * @param {string} content - String corresponding to markup
+ * @return {object} el.firstElementChild - HTML module
+ */
- // Insert each tag of the template contents before placeholder
- renderedContents.forEach(element => {
- const newEl = element;
+ }, {
+ key: 'convertToElement',
+ value: function convertToElement(content) {
+ var el = document.createElement('div');
- if (1 === newEl.nodeType) {
- newEl.dataset.parentHash = meta.hash;
- hasStyleguideHelpers = !hasStyleguideHelpers ? InsertNodes.isSectionHelper(newEl, meta) : hasStyleguideHelpers;
+ el.innerHTML = content;
+ return el.firstElementChild;
+ }
- parent.insertBefore(newEl, modifiedPlaceholder);
- }
- });
+ /**
+ * Filter module object by module key or module type
+ *
+ * @param {object} filter - Filter for modules. Options:
+ * @param {string} filter.property - Which property to filter ('key' or 'type')
+ * @param {array} filter.values - Values for property
+ * @param {bool} filter.include - Whether the values should be included or excluded (true = include, false = exclude)
+ * @param {object} moduleMeta - Filter for modules. Fields explained in the filterModules() function docs
+ * @return {bool} match - determine if modules need to be filtered
+ */
+
+ }, {
+ key: 'filterModules',
+ value: function filterModules(filter, moduleMeta) {
+ var match = true;
+
+ // Check if we should filter out any modules
+ if ('object' === (typeof filter === 'undefined' ? 'undefined' : _typeof(filter)) && {}.hasOwnProperty.call(filter, 'property') && {}.hasOwnProperty.call(filter, 'values') && {}.hasOwnProperty.call(filter, 'include')) {
+ match = filter.values.filter(function (value) {
+ return moduleMeta[filter.property] === value;
+ });
+ return Boolean(match.length) === filter.include;
+ }
- // Add module hash to this placeholder
- modifiedPlaceholder.dataset.selfHash = meta.hash;
+ console.log(' // eslint-disable-line no-console\n filter ' + filter + ' is not in a valid format.\n module filters must include \'property\', \'values\', and \'include\' properties\n ');
- // Hide the placeholder
- modifiedPlaceholder.style.display = 'none';
+ return match;
+ }
- // Recursively load modules, excluding the current one
- this.cycleModules(renderedContents, {
- property: 'key',
- values: [meta.key, this._sectionTemplatePath],
- include: false
- });
+ /**
+ * Generate a hash string from a module key
+ *
+ * @param {string} key - module key (require path) to convert into a hash
+ * @return {string} key - generated MD5 Hash
+ */
+
+ }, {
+ key: 'generateModuleHash',
+ value: function generateModuleHash(key) {
+ return md5(key);
+ }
- if (hasStyleguideHelpers) {
- this.cycleStyleguide();
- }
- });
+ /**
+ * Retrieve a data attribute from a tag using one of two methods
+ *
+ * @param {HTMLElement} tag - DOM node on which to check for a data attribute
+ * @param {string} attr - attribute to check for
+ * @returns {string} data - contents of data attribute
+ */
+
+ }, {
+ key: 'getDataAttribute',
+ value: function getDataAttribute(tag, attr) {
+ var data = false;
+
+ // Check if element has dataset and, if so, use it
+ if (tag.dataset) {
+ data = tag.dataset[attr];
}
- } else {
- console.warn( // eslint-disable-line no-console
- `Could not render module
- section: ${meta.id}
- type: ${meta.type}`);
- }
- }
- /**
- * Verify specified element is using an acceptable huron type
- *
- * @param {string} type - type of partial (template, data, description, section or prototype )
- * @return {string} type - huron type or 'template' if invalid
- */
- validateType(type) {
- if ('data' === type) {
- return 'template';
- }
+ // Fallback to getAttribute for ugly old Safari
+ if (!data && tag.getAttribute) {
+ data = tag.getAttribute('data-' + attr);
+ }
- if (!this._types.includes(type)) {
- return false;
+ return data;
}
- return type;
- }
+ /**
+ * Check if this tag is a styleguide helper
+ *
+ * @param {object} tag - tag to check
+ * @param {object} meta - module metadata
+ * @return {bool}
+ */
+
+ }, {
+ key: 'isSectionHelper',
+ value: function isSectionHelper(tag, meta) {
+ if ('prototype' === meta.type) {
+ return tag.hasAttribute('huron-sections') || tag.hasAttribute('huron-menu');
+ }
- /*
- * Set new modules object
- */
- set modules(modules) {
- this._modules = modules;
- this._moduleIds = Object.keys(modules);
- }
+ return false;
+ }
+ }]);
- /*
- * Set store
- */
- set store(store) {
- this._store = store;
- this._config = store.config;
- this._sections = store.sections;
- this._templates = store.templates;
- this._prototypes = store.prototypes;
- this._types = store.types;
- this._sectionTemplatePath = store.sectionTemplatePath;
- }
-}
+ return InsertNodes;
+}();
/* eslint-enable no-underscore-dangle */
// Create a new instance of the InsertNodes class
/*eslint-disable*/
// Create object for modifiying the templates on the page and
// initial first templates.
-const insert = new InsertNodes(modules, store);
+
+
+var insert = new InsertNodes(modules, store);
/*eslint-enable*/
//# sourceMappingURL=huron.js.map
\ No newline at end of file
diff --git a/dist/web/huron.js.map b/dist/web/huron.js.map
index 494695c..52e735c 100644
--- a/dist/web/huron.js.map
+++ b/dist/web/huron.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../../src/web/huron.js"],"names":["md5","require","module","hot","accept","InsertNodes","constructor","modules","store","_modules","_moduleIds","Object","keys","_config","_sections","_templates","_prototypes","_types","meta","cycleModules","cycleStyleguide","applyModifier","modifier","rendered","data","assign","render","convertToElement","content","el","document","createElement","innerHTML","firstElementChild","filterModules","filter","moduleMeta","match","hasOwnProperty","call","values","value","property","Boolean","length","include","console","log","generateModuleHash","key","getDataAttribute","tag","attr","dataset","getAttribute","isSectionHelper","type","hasAttribute","context","moduleList","elementList","regenCache","querySelectorAll","getModuleListFromTags","forEach","replaceElements","loadModule","cycleSections","sectionsQuery","querySelector","menuQuery","outputSections","menuTrigger","classList","add","body","insertBefore","appendChild","childNodes","addEventListener","toggle","outputMenu","getMetaFromPath","sections","sectionsByPath","templateTypes","id","indexOf","prototype","name","_sectionTemplatePath","testTypes","testSections","section","tempTypes","currentType","referenceURI","hashKey","renderData","getModuleRender","hash","warn","getModuleKeyFromTag","sectionsByURI","elements","recurse","newList","element","moduleKey","push","concat","cached","shouldLoad","replaceTemplate","parent","sorted","templateId","newEl","hasSubmenu","menuTarget","nextMenu","title","header","sectionMenu","menuItem","link","tagName","cloneNode","placeholder","istopLevel","topLevelWrapper","topLevelSection","insertionEl","huronId","huronType","removeOldTags","parentHash","selfHash","childrenHash","nextTag","previousSibling","parentNode","removeChild","validateType","tags","replace","hasStyleguideHelpers","tagType","tagId","currentTag","modifiedPlaceholder","renderedTemplate","renderedContents","children","nodeType","style","display","includes","_store","config","templates","prototypes","types","sectionTemplatePath","insert"],"mappings":"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","file":"huron.js","sourcesContent":["const md5 = require('js-md5');\n\n/* eslint-disable no-underscore-dangle */\n// Accept the huron.js module for Huron development\nif (module.hot) {\n module.hot.accept();\n}\n\n/** Class for inserting HTML snippets at particular insertion points.\n * Uses require() to grab html partials, then inserts that html\n * into an element with attribute [huron-id] corresponding to the reference URI of the target KSS section,\n * and [huron-type] corresponding with the required KSS field\n */\nclass InsertNodes {\n\n constructor(modules, store) {\n /** webpack module list in which keys are relative require paths and values are the module contents */\n this._modules = modules;\n /** array of module keys */\n this._moduleIds = Object.keys(modules);\n /** reference to the huron config */\n this._config = null;\n /** KSS sections organized in various formats including by reference URI, by module key, and modules sorted by parent/child */\n this._sections = null;\n /** Key/value pairs of partner data and template files */\n this._templates = null;\n /** array of prototypes */\n this._prototypes = null;\n /** array of valid huron placeholder types */\n this._types = null;\n\n /** Cache for module metadata */\n this.meta = {};\n\n /** Reference to entire memory store */\n this.store = store;\n\n // Inits\n this.cycleModules();\n this.cycleStyleguide();\n }\n\n /**\n * Apply a modifier to a render function\n *\n * @param {string} modifier - target modifier\n * @param {object} meta - module metadata\n * @return {string} rendered - the modified HTML module\n */\n static applyModifier(modifier, meta) {\n let rendered = false;\n let data = meta.data;\n\n if (data) {\n // If we have a modifier, use it, otherwise use the entire data set\n if (modifier && meta.data[modifier]) {\n data = Object.assign({}, meta.data[modifier], { modifier });\n }\n\n rendered = meta.render(data);\n } else {\n rendered = meta.render();\n }\n\n return rendered;\n }\n\n /**\n * Get markup from any type of module (html, json or template)\n *\n * @param {string} content - String corresponding to markup\n * @return {object} el.firstElementChild - HTML module\n */\n static convertToElement(content) {\n const el = document.createElement('div');\n\n el.innerHTML = content;\n return el.firstElementChild;\n }\n\n /**\n * Filter module object by module key or module type\n *\n * @param {object} filter - Filter for modules. Options:\n * @param {string} filter.property - Which property to filter ('key' or 'type')\n * @param {array} filter.values - Values for property\n * @param {bool} filter.include - Whether the values should be included or excluded (true = include, false = exclude)\n * @param {object} moduleMeta - Filter for modules. Fields explained in the filterModules() function docs\n * @return {bool} match - determine if modules need to be filtered\n */\n static filterModules(filter, moduleMeta) {\n let match = true;\n\n // Check if we should filter out any modules\n if (\n 'object' === typeof filter &&\n {}.hasOwnProperty.call(filter, 'property') &&\n {}.hasOwnProperty.call(filter, 'values') &&\n {}.hasOwnProperty.call(filter, 'include')\n ) {\n match = filter.values.filter(\n (value) => moduleMeta[filter.property] === value\n );\n return Boolean(match.length) === filter.include;\n }\n\n console.log(` // eslint-disable-line no-console\n filter ${filter} is not in a valid format.\n module filters must include 'property', 'values', and 'include' properties\n `);\n\n return match;\n }\n\n /**\n * Generate a hash string from a module key\n *\n * @param {string} key - module key (require path) to convert into a hash\n * @return {string} key - generated MD5 Hash\n */\n static generateModuleHash(key) {\n return md5(key);\n }\n\n /**\n * Retrieve a data attribute from a tag using one of two methods\n *\n * @param {HTMLElement} tag - DOM node on which to check for a data attribute\n * @param {string} attr - attribute to check for\n * @returns {string} data - contents of data attribute\n */\n static getDataAttribute(tag, attr) {\n let data = false;\n\n // Check if element has dataset and, if so, use it\n if (tag.dataset) {\n data = tag.dataset[attr];\n }\n\n // Fallback to getAttribute for ugly old Safari\n if (! data && tag.getAttribute) {\n data = tag.getAttribute(`data-${attr}`);\n }\n\n return data;\n }\n\n /**\n * Check if this tag is a styleguide helper\n *\n * @param {object} tag - tag to check\n * @param {object} meta - module metadata\n * @return {bool}\n */\n static isSectionHelper(tag, meta) {\n if ('prototype' === meta.type) {\n return tag.hasAttribute('huron-sections') ||\n tag.hasAttribute('huron-menu');\n }\n\n return false;\n }\n\n /**\n * Replace all template markers with the actual template markup.\n *\n * @param {string} context - The hash context for the module\n * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs\n */\n cycleModules(context = false, filter = false) {\n let moduleList = {};\n let elementList = context;\n\n // We're replacing top-level elements\n if (! elementList) {\n this.regenCache();\n\n // Find all top-level huron placeholders\n elementList = [...document.querySelectorAll(\n '[data-huron-id][data-huron-type]'\n )];\n }\n\n moduleList = this.getModuleListFromTags(elementList);\n\n // Loop through modules array\n Object.keys(moduleList).forEach((key) => {\n const module = this._modules[key];\n const replaceElements = moduleList[key];\n\n this.loadModule(key, module, replaceElements, true, filter);\n });\n }\n\n /**\n * Helper for reloading sections only\n */\n cycleSections() {\n this.cycleModules(false, {\n property: 'type',\n values: ['section'],\n include: true,\n });\n }\n\n /**\n * Reload styleguide sections and menu helpers\n */\n cycleStyleguide() {\n const sectionsQuery = document.querySelector('[huron-sections]');\n const menuQuery = document.querySelector('[huron-menu]');\n\n // Sections\n if (sectionsQuery) {\n sectionsQuery.innerHTML = '';\n this.outputSections(null, sectionsQuery);\n this.cycleSections();\n }\n\n // Menu\n if (menuQuery) {\n menuQuery.innerHTML = '';\n\n if (null === document.querySelector('.section-menu__expand')) {\n const menuTrigger = document.createElement('button');\n\n menuTrigger.classList.add('section-menu__expand');\n menuTrigger.innerHTML = 'Sections Menu';\n document.body.insertBefore(\n menuQuery.appendChild(menuTrigger),\n document.body.childNodes[0]\n );\n\n // Add menu trigger handler\n menuTrigger.addEventListener('click', () => {\n document.body.classList.toggle('section-menu-open');\n });\n }\n\n // Create menu\n this.outputMenu(null, menuQuery);\n }\n }\n\n /**\n * Get module metadata from a module require path\n *\n * @param {string} key - Module require path\n * @return {object} containing module id, module type, key and the module contents\n */\n getMetaFromPath(key, module) {\n const sections = this._sections.sectionsByPath;\n const templateTypes = this._types.filter((type) => 'prototype' !== type);\n let id = false;\n let type = false;\n\n /* eslint-disable space-unary-ops */\n if (-1 !== key.indexOf('./prototypes')) {\n /* eslint-enable space-unary-ops */\n const prototype = Object.keys(this._prototypes)\n .filter((name) => this._prototypes[name] === key);\n\n if (prototype.length) {\n id = prototype[0];\n type = 'prototype';\n }\n } else if (key === this._sectionTemplatePath) {\n id = 'sections-template';\n type = 'sections-template';\n } else {\n let testTypes = [];\n const testSections = Object.keys(sections).filter((section) => {\n const tempTypes = templateTypes.filter(\n (currentType) => sections[section][`${currentType}Path`] === key\n );\n\n if (tempTypes.length) {\n testTypes = tempTypes;\n return true;\n }\n\n return false;\n });\n\n if (\n testSections &&\n testSections.length &&\n testTypes &&\n testTypes.length\n ) {\n id = sections[testSections[0]].referenceURI;\n type = testTypes[0];\n }\n }\n\n if (id && type) {\n const hashKey = 'data' === type ? this._templates[key] : key;\n const renderData = this.getModuleRender(type, key, module);\n const hash = InsertNodes.generateModuleHash(hashKey);\n\n if (renderData) {\n return Object.assign({ id, type, key, hash, module }, renderData);\n }\n }\n\n console.warn( // eslint-disable-line no-console\n `Module '${key}' does not exist on the page\n or is no longer in use`\n );\n return false;\n }\n\n /**\n * Check if a tag is a huron placeholder and, if so,\n * return its associated module key\n *\n * @param {object} tag - tag to check\n * @return {bool} associated module key\n */\n getModuleKeyFromTag(tag) {\n // Safari/webkit has some trouble parsing dataset in certain cases.\n // This is a fallback method of accessing the same data.\n const type = InsertNodes.getDataAttribute(tag, 'huron-type');\n const id = InsertNodes.getDataAttribute(tag, 'huron-id');\n const section = this._sections.sectionsByURI[id];\n\n if (id && type) {\n if (section) {\n return section[`${type}Path`];\n } else if ('prototype' === type) {\n return this._prototypes[id];\n }\n }\n\n return false;\n }\n\n /**\n * Check if an array of elements contains a Huron placeholder\n *\n * @param {array} tags - array of DOM nodes\n * @param {bool} recurse - should we recurse this function with a new array\n * @return {object} moduleList - Huron placeholder DOM node\n */\n getModuleListFromTags(elements, recurse = true) {\n const moduleList = {};\n let newList = {};\n\n if (elements && elements.length) {\n elements.forEach((element) => {\n const moduleKey = this.getModuleKeyFromTag(element);\n\n if (moduleKey) {\n if (! moduleList[moduleKey]) {\n moduleList[moduleKey] = [];\n }\n moduleList[moduleKey].push(element);\n } else if (recurse) {\n newList = this.getModuleListFromTags(\n [...element.querySelectorAll('[data-huron-id][data-huron-type]')],\n false\n );\n\n Object.keys(newList).forEach((key) => {\n moduleList[key] = moduleList[key] ?\n moduleList[key].concat(newList[key]) :\n newList[key];\n });\n }\n });\n }\n\n return moduleList;\n }\n\n /**\n * Transform every module into a predictable object\n *\n * @param {object} type - Module metadata\n * @param {mixed} module - Module contents\n * @return {object} containing render function, render data and module id\n */\n getModuleRender(type, key, module) {\n let render = false;\n let data = false;\n\n if ('template' === type && 'function' === typeof module) {\n // It's a render function for a template\n render = module;\n data = this._modules[this._templates[key]];\n } else if (\n 'sections-template' === type &&\n 'function' === typeof module\n ) {\n // It's a kss section template\n render = module;\n } else if (\n 'section' === type &&\n 'object' === typeof module\n ) {\n // It's section data\n render = this._modules[this._sectionTemplatePath];\n data = module;\n } else if (\n ('template' === type || 'description' === type || 'prototype' === type) &&\n 'string' === typeof module\n ) {\n // it's straight HTML\n render = () => module;\n } else if ('data' === type && 'object' === typeof module) {\n // It's a data file (.json)\n render = this._modules[this._templates[key]];\n data = module;\n }\n\n // Only need render, as data will be left empty for static HTML\n if (render) {\n return { render, data };\n }\n\n return false;\n }\n\n /**\n * Replace all sections. For hot reloading use when the section template has changed.\n *\n * @param {object} replaceElements - The context (e.g. document) that you will query for the template ID to replace\n * @param {string} key - Module require path\n * @param {mixed} module - Module contents\n * @param {bool} cached - Whether or not to use cached values for module replacement\n * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs\n */\n loadModule(key, module, replaceElements, cached = false, filter = false) {\n let shouldLoad = true;\n let moduleMeta = false;\n\n // Check if we should load from internal module metadata cache\n if (cached) {\n moduleMeta = this.meta[key];\n } else {\n moduleMeta = this.meta[key] = this.getMetaFromPath(key, module);\n }\n\n if (moduleMeta) {\n if (filter) {\n shouldLoad = InsertNodes.filterModules(filter, moduleMeta);\n }\n\n if (shouldLoad) {\n this.replaceTemplate(moduleMeta, replaceElements);\n }\n }\n }\n\n /*\n * Helper function for inserting styleguide sections.\n *\n * Recurses over sorted styleguide sections and inserts a
to be used as a menu for each section\n */\n outputMenu(parent, el, sections = this._sections.sorted) {\n let templateId = null;\n let newEl = el;\n\n Object.keys(sections).forEach((section) => {\n const hasSubmenu = Object.keys(sections[section]).length;\n let menuTarget;\n let nextMenu;\n\n if (parent) {\n templateId = `${parent}-${section}`;\n } else {\n templateId = section;\n }\n\n if (newEl) {\n const title = this._sections\n .sectionsByURI[templateId] ?\n this._sections\n .sectionsByURI[templateId]\n .header :\n templateId;\n const sectionMenu = document.createElement('ul');\n const menuItem = document.createElement('li');\n const link = `${title}`;\n\n sectionMenu.classList.add('section-menu');\n menuItem.classList.add('section-menu__item');\n menuItem.innerHTML = link;\n\n // Check if this is a UL and, if not, create one\n if ('UL' !== newEl.tagName) {\n menuTarget = sectionMenu.cloneNode();\n newEl.appendChild(menuTarget);\n newEl = menuTarget;\n }\n\n // Has subsections\n if (hasSubmenu) {\n nextMenu = sectionMenu.cloneNode();\n nextMenu.classList.add('section-menu--submenu');\n menuItem.classList.add('section-menu__item--has-submenu');\n menuItem.appendChild(nextMenu);\n }\n\n newEl.appendChild(menuItem);\n\n if (hasSubmenu) {\n this.outputMenu(\n templateId,\n nextMenu,\n sections[section]\n );\n }\n }\n });\n }\n\n /**\n * Helper function for inserting styleguide sections.\n *\n * Recurses over sorted styleguide sections and inserts a tag with [huron-id] equal to the section template name.\n */\n outputSections(parent, el, sections = this._sections.sorted) {\n let templateId = null;\n let placeholder = null;\n\n Object.keys(sections).forEach((section) => {\n let istopLevel = false;\n let topLevelWrapper = null;\n let topLevelSection = null;\n let insertionEl = el;\n\n // Generate section ID and check if it is top-level\n if (parent) {\n templateId = `${parent}-${section}`;\n } else {\n templateId = section;\n istopLevel = true;\n }\n\n if (el) {\n // Generate huron placeholder for this section\n placeholder = document.createElement('div');\n placeholder.dataset.huronId = templateId;\n placeholder.dataset.huronType = 'section';\n\n if (istopLevel) {\n // Generate wrapper to contain top-level section and all subsections underneath it\n topLevelWrapper = document.createElement('div');\n topLevelWrapper.classList.add('section--top-level__wrapper');\n\n // Generate wrapper for top-level section\n topLevelSection = document.createElement('div');\n topLevelSection.classList.add('section', 'section--top-level');\n\n // Append wrappers to huron-sections element\n topLevelSection.appendChild(placeholder);\n topLevelWrapper.appendChild(topLevelSection);\n el.appendChild(topLevelWrapper);\n insertionEl = topLevelWrapper;\n } else {\n // If this is not top-level, append placeholder\n el.appendChild(placeholder);\n }\n }\n\n // Recursively call this function to insert other sections\n if (Object.keys(sections[section]).length && placeholder) {\n this.outputSections(\n templateId,\n insertionEl,\n sections[section]\n );\n }\n });\n }\n\n /**\n * Regenerate module meta cache\n */\n regenCache() {\n Object.keys(this._modules).forEach((moduleKey) => {\n this.meta[moduleKey] = this.getMetaFromPath(\n moduleKey, this._modules[moduleKey]\n );\n });\n }\n\n /**\n * Recursively remove old tags\n *\n * @param {string} hash - hash of module for which we need to remove old tags\n * @param {object} tag - tag to start our search with\n * (usually the tag immediately preceding the current placeholder)\n */\n removeOldTags(hash, tag) {\n if (tag) {\n const parentHash = InsertNodes.getDataAttribute(tag, 'parent-hash');\n const selfHash = InsertNodes.getDataAttribute(tag, 'self-hash');\n\n if (parentHash === hash && selfHash !== hash) {\n // This is a child of the current module,\n // so remove it and its children (if applicable)\n const childrenHash = selfHash;\n let nextTag = tag.previousSibling;\n\n if (childrenHash) {\n this.removeOldTags(childrenHash, nextTag);\n // Reset nextTag if we removed a child\n nextTag = tag.previousSibling;\n }\n\n tag.parentNode.removeChild(tag);\n this.removeOldTags(hash, nextTag);\n }\n }\n }\n\n /**\n * Replace a single template marker with template content.\n *\n * @param {object} replaceElements - Array of elements to check for Huron placeholders\n * @param {object} meta - Module metadata\n */\n replaceTemplate(meta, replaceElements) {\n const type = this.validateType(meta.type);\n const tags = [];\n let replace = replaceElements;\n let hasStyleguideHelpers = false;\n\n if (! replace) {\n replace = document.querySelectorAll(\n '[data-huron-id][data-huron-type]'\n );\n }\n\n if (type) {\n replace.forEach((tag) => {\n const tagType = InsertNodes.getDataAttribute(tag, 'huron-type');\n const tagId = InsertNodes.getDataAttribute(tag, 'huron-id');\n\n if (tagId === meta.id && tagType === type) {\n tags.push(tag);\n }\n });\n\n if (tags && tags.length && meta.render) {\n tags.forEach((currentTag) => {\n const modifiedPlaceholder = currentTag;\n const modifier = InsertNodes\n .getDataAttribute(modifiedPlaceholder, 'huron-modifier');\n const parent = modifiedPlaceholder.parentNode;\n const rendered = InsertNodes.applyModifier(modifier, meta);\n const renderedTemplate = InsertNodes.convertToElement(rendered)\n .querySelector('template');\n let renderedContents = null;\n\n // Remove existing module tags\n this.removeOldTags(meta.hash, modifiedPlaceholder.previousSibling);\n\n // Get the contents of the rendered template\n renderedContents = [\n ...renderedTemplate.content.children,\n ];\n\n // Insert each tag of the template contents before placeholder\n renderedContents.forEach((element) => {\n const newEl = element;\n\n if (1 === newEl.nodeType) {\n newEl.dataset.parentHash = meta.hash;\n hasStyleguideHelpers = ! hasStyleguideHelpers ?\n InsertNodes.isSectionHelper(newEl, meta) :\n hasStyleguideHelpers;\n\n parent.insertBefore(newEl, modifiedPlaceholder);\n }\n });\n\n // Add module hash to this placeholder\n modifiedPlaceholder.dataset.selfHash = meta.hash;\n\n // Hide the placeholder\n modifiedPlaceholder.style.display = 'none';\n\n // Recursively load modules, excluding the current one\n this.cycleModules(renderedContents, {\n property: 'key',\n values: [meta.key, this._sectionTemplatePath],\n include: false,\n });\n\n if (hasStyleguideHelpers) {\n this.cycleStyleguide();\n }\n });\n }\n } else {\n console.warn( // eslint-disable-line no-console\n `Could not render module\n section: ${meta.id}\n type: ${meta.type}`\n );\n }\n }\n\n /**\n * Verify specified element is using an acceptable huron type\n *\n * @param {string} type - type of partial (template, data, description, section or prototype )\n * @return {string} type - huron type or 'template' if invalid\n */\n validateType(type) {\n if ('data' === type) {\n return 'template';\n }\n\n if (! this._types.includes(type)) {\n return false;\n }\n\n return type;\n }\n\n /*\n * Set new modules object\n */\n set modules(modules) {\n this._modules = modules;\n this._moduleIds = Object.keys(modules);\n }\n\n /*\n * Set store\n */\n set store(store) {\n this._store = store;\n this._config = store.config;\n this._sections = store.sections;\n this._templates = store.templates;\n this._prototypes = store.prototypes;\n this._types = store.types;\n this._sectionTemplatePath = store.sectionTemplatePath;\n }\n}\n/* eslint-enable no-underscore-dangle */\n\n// Create a new instance of the InsertNodes class\n/*eslint-disable*/\n// Create object for modifiying the templates on the page and\n// initial first templates.\nconst insert = new InsertNodes(modules, store);\n/*eslint-enable*/\n"]}
\ No newline at end of file
+{"version":3,"sources":["../../src/web/huron.js"],"names":["md5","require","module","hot","accept","InsertNodes","modules","store","_modules","_moduleIds","Object","keys","_config","_sections","_templates","_prototypes","_types","meta","cycleModules","cycleStyleguide","context","filter","moduleList","elementList","regenCache","document","querySelectorAll","getModuleListFromTags","forEach","key","replaceElements","loadModule","property","values","include","sectionsQuery","querySelector","menuQuery","innerHTML","outputSections","cycleSections","menuTrigger","createElement","classList","add","body","insertBefore","appendChild","childNodes","addEventListener","toggle","outputMenu","sections","sectionsByPath","templateTypes","type","id","indexOf","prototype","name","length","_sectionTemplatePath","testTypes","testSections","section","tempTypes","currentType","referenceURI","hashKey","renderData","getModuleRender","hash","generateModuleHash","assign","console","warn","tag","getDataAttribute","sectionsByURI","elements","recurse","newList","element","moduleKey","getModuleKeyFromTag","push","concat","render","data","cached","shouldLoad","moduleMeta","getMetaFromPath","filterModules","replaceTemplate","parent","el","sorted","templateId","newEl","hasSubmenu","menuTarget","nextMenu","title","header","sectionMenu","menuItem","link","tagName","cloneNode","placeholder","istopLevel","topLevelWrapper","topLevelSection","insertionEl","dataset","huronId","huronType","parentHash","selfHash","childrenHash","nextTag","previousSibling","removeOldTags","parentNode","removeChild","validateType","tags","replace","hasStyleguideHelpers","tagType","tagId","currentTag","modifiedPlaceholder","modifier","rendered","applyModifier","renderedTemplate","convertToElement","renderedContents","content","children","nodeType","isSectionHelper","style","display","includes","_store","config","templates","prototypes","types","sectionTemplatePath","firstElementChild","match","hasOwnProperty","call","value","Boolean","log","attr","getAttribute","hasAttribute","insert"],"mappings":"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","file":"huron.js","sourcesContent":["const md5 = require('js-md5');\n\n/* eslint-disable no-underscore-dangle */\n// Accept the huron.js module for Huron development\nif (module.hot) {\n module.hot.accept();\n}\n\n/** Class for inserting HTML snippets at particular insertion points.\n * Uses require() to grab html partials, then inserts that html\n * into an element with attribute [huron-id] corresponding to the reference URI of the target KSS section,\n * and [huron-type] corresponding with the required KSS field\n */\nclass InsertNodes {\n\n constructor(modules, store) {\n /** webpack module list in which keys are relative require paths and values are the module contents */\n this._modules = modules;\n /** array of module keys */\n this._moduleIds = Object.keys(modules);\n /** reference to the huron config */\n this._config = null;\n /** KSS sections organized in various formats including by reference URI, by module key, and modules sorted by parent/child */\n this._sections = null;\n /** Key/value pairs of partner data and template files */\n this._templates = null;\n /** array of prototypes */\n this._prototypes = null;\n /** array of valid huron placeholder types */\n this._types = null;\n\n /** Cache for module metadata */\n this.meta = {};\n\n /** Reference to entire memory store */\n this.store = store;\n\n // Inits\n this.cycleModules();\n this.cycleStyleguide();\n }\n\n /**\n * Apply a modifier to a render function\n *\n * @param {string} modifier - target modifier\n * @param {object} meta - module metadata\n * @return {string} rendered - the modified HTML module\n */\n static applyModifier(modifier, meta) {\n let rendered = false;\n let data = meta.data;\n\n if (data) {\n // If we have a modifier, use it, otherwise use the entire data set\n if (modifier && meta.data[modifier]) {\n data = Object.assign({}, meta.data[modifier], { modifier });\n }\n\n rendered = meta.render(data);\n } else {\n rendered = meta.render();\n }\n\n return rendered;\n }\n\n /**\n * Get markup from any type of module (html, json or template)\n *\n * @param {string} content - String corresponding to markup\n * @return {object} el.firstElementChild - HTML module\n */\n static convertToElement(content) {\n const el = document.createElement('div');\n\n el.innerHTML = content;\n return el.firstElementChild;\n }\n\n /**\n * Filter module object by module key or module type\n *\n * @param {object} filter - Filter for modules. Options:\n * @param {string} filter.property - Which property to filter ('key' or 'type')\n * @param {array} filter.values - Values for property\n * @param {bool} filter.include - Whether the values should be included or excluded (true = include, false = exclude)\n * @param {object} moduleMeta - Filter for modules. Fields explained in the filterModules() function docs\n * @return {bool} match - determine if modules need to be filtered\n */\n static filterModules(filter, moduleMeta) {\n let match = true;\n\n // Check if we should filter out any modules\n if (\n 'object' === typeof filter &&\n {}.hasOwnProperty.call(filter, 'property') &&\n {}.hasOwnProperty.call(filter, 'values') &&\n {}.hasOwnProperty.call(filter, 'include')\n ) {\n match = filter.values.filter(\n (value) => moduleMeta[filter.property] === value\n );\n return Boolean(match.length) === filter.include;\n }\n\n console.log(` // eslint-disable-line no-console\n filter ${filter} is not in a valid format.\n module filters must include 'property', 'values', and 'include' properties\n `);\n\n return match;\n }\n\n /**\n * Generate a hash string from a module key\n *\n * @param {string} key - module key (require path) to convert into a hash\n * @return {string} key - generated MD5 Hash\n */\n static generateModuleHash(key) {\n return md5(key);\n }\n\n /**\n * Retrieve a data attribute from a tag using one of two methods\n *\n * @param {HTMLElement} tag - DOM node on which to check for a data attribute\n * @param {string} attr - attribute to check for\n * @returns {string} data - contents of data attribute\n */\n static getDataAttribute(tag, attr) {\n let data = false;\n\n // Check if element has dataset and, if so, use it\n if (tag.dataset) {\n data = tag.dataset[attr];\n }\n\n // Fallback to getAttribute for ugly old Safari\n if (! data && tag.getAttribute) {\n data = tag.getAttribute(`data-${attr}`);\n }\n\n return data;\n }\n\n /**\n * Check if this tag is a styleguide helper\n *\n * @param {object} tag - tag to check\n * @param {object} meta - module metadata\n * @return {bool}\n */\n static isSectionHelper(tag, meta) {\n if ('prototype' === meta.type) {\n return tag.hasAttribute('huron-sections') ||\n tag.hasAttribute('huron-menu');\n }\n\n return false;\n }\n\n /**\n * Replace all template markers with the actual template markup.\n *\n * @param {string} context - The hash context for the module\n * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs\n */\n cycleModules(context = false, filter = false) {\n let moduleList = {};\n let elementList = context;\n\n // We're replacing top-level elements\n if (! elementList) {\n this.regenCache();\n\n // Find all top-level huron placeholders\n elementList = [...document.querySelectorAll(\n '[data-huron-id][data-huron-type]'\n )];\n }\n\n moduleList = this.getModuleListFromTags(elementList);\n\n // Loop through modules array\n Object.keys(moduleList).forEach((key) => {\n const module = this._modules[key];\n const replaceElements = moduleList[key];\n\n this.loadModule(key, module, replaceElements, true, filter);\n });\n }\n\n /**\n * Helper for reloading sections only\n */\n cycleSections() {\n this.cycleModules(false, {\n property: 'type',\n values: ['section'],\n include: true,\n });\n }\n\n /**\n * Reload styleguide sections and menu helpers\n */\n cycleStyleguide() {\n const sectionsQuery = document.querySelector('[huron-sections]');\n const menuQuery = document.querySelector('[huron-menu]');\n\n // Sections\n if (sectionsQuery) {\n sectionsQuery.innerHTML = '';\n this.outputSections(null, sectionsQuery);\n this.cycleSections();\n }\n\n // Menu\n if (menuQuery) {\n menuQuery.innerHTML = '';\n\n if (null === document.querySelector('.section-menu__expand')) {\n const menuTrigger = document.createElement('button');\n\n menuTrigger.classList.add('section-menu__expand');\n menuTrigger.innerHTML = 'Sections Menu';\n document.body.insertBefore(\n menuQuery.appendChild(menuTrigger),\n document.body.childNodes[0]\n );\n\n // Add menu trigger handler\n menuTrigger.addEventListener('click', () => {\n document.body.classList.toggle('section-menu-open');\n });\n }\n\n // Create menu\n this.outputMenu(null, menuQuery);\n }\n }\n\n /**\n * Get module metadata from a module require path\n *\n * @param {string} key - Module require path\n * @return {object} containing module id, module type, key and the module contents\n */\n getMetaFromPath(key, module) {\n const sections = this._sections.sectionsByPath;\n const templateTypes = this._types.filter((type) => 'prototype' !== type);\n let id = false;\n let type = false;\n\n /* eslint-disable space-unary-ops */\n if (-1 !== key.indexOf('./prototypes')) {\n /* eslint-enable space-unary-ops */\n const prototype = Object.keys(this._prototypes)\n .filter((name) => this._prototypes[name] === key);\n\n if (prototype.length) {\n id = prototype[0];\n type = 'prototype';\n }\n } else if (key === this._sectionTemplatePath) {\n id = 'sections-template';\n type = 'sections-template';\n } else {\n let testTypes = [];\n const testSections = Object.keys(sections).filter((section) => {\n const tempTypes = templateTypes.filter(\n (currentType) => sections[section][`${currentType}Path`] === key\n );\n\n if (tempTypes.length) {\n testTypes = tempTypes;\n return true;\n }\n\n return false;\n });\n\n if (\n testSections &&\n testSections.length &&\n testTypes &&\n testTypes.length\n ) {\n id = sections[testSections[0]].referenceURI;\n type = testTypes[0];\n }\n }\n\n if (id && type) {\n const hashKey = 'data' === type ? this._templates[key] : key;\n const renderData = this.getModuleRender(type, key, module);\n const hash = InsertNodes.generateModuleHash(hashKey);\n\n if (renderData) {\n return Object.assign({ id, type, key, hash, module }, renderData);\n }\n }\n\n console.warn( // eslint-disable-line no-console\n `Module '${key}' does not exist on the page\n or is no longer in use`\n );\n return false;\n }\n\n /**\n * Check if a tag is a huron placeholder and, if so,\n * return its associated module key\n *\n * @param {object} tag - tag to check\n * @return {bool} associated module key\n */\n getModuleKeyFromTag(tag) {\n // Safari/webkit has some trouble parsing dataset in certain cases.\n // This is a fallback method of accessing the same data.\n const type = InsertNodes.getDataAttribute(tag, 'huron-type');\n const id = InsertNodes.getDataAttribute(tag, 'huron-id');\n const section = this._sections.sectionsByURI[id];\n\n if (id && type) {\n if (section) {\n return section[`${type}Path`];\n } else if ('prototype' === type) {\n return this._prototypes[id];\n }\n }\n\n return false;\n }\n\n /**\n * Check if an array of elements contains a Huron placeholder\n *\n * @param {array} tags - array of DOM nodes\n * @param {bool} recurse - should we recurse this function with a new array\n * @return {object} moduleList - Huron placeholder DOM node\n */\n getModuleListFromTags(elements, recurse = true) {\n const moduleList = {};\n let newList = {};\n\n if (elements && elements.length) {\n elements.forEach((element) => {\n const moduleKey = this.getModuleKeyFromTag(element);\n\n if (moduleKey) {\n if (! moduleList[moduleKey]) {\n moduleList[moduleKey] = [];\n }\n moduleList[moduleKey].push(element);\n } else if (recurse) {\n newList = this.getModuleListFromTags(\n [...element.querySelectorAll('[data-huron-id][data-huron-type]')],\n false\n );\n\n Object.keys(newList).forEach((key) => {\n moduleList[key] = moduleList[key] ?\n moduleList[key].concat(newList[key]) :\n newList[key];\n });\n }\n });\n }\n\n return moduleList;\n }\n\n /**\n * Transform every module into a predictable object\n *\n * @param {object} type - Module metadata\n * @param {mixed} module - Module contents\n * @return {object} containing render function, render data and module id\n */\n getModuleRender(type, key, module) {\n let render = false;\n let data = false;\n\n if ('template' === type && 'function' === typeof module) {\n // It's a render function for a template\n render = module;\n data = this._modules[this._templates[key]];\n } else if (\n 'sections-template' === type &&\n 'function' === typeof module\n ) {\n // It's a kss section template\n render = module;\n } else if (\n 'section' === type &&\n 'object' === typeof module\n ) {\n // It's section data\n render = this._modules[this._sectionTemplatePath];\n data = module;\n } else if (\n ('template' === type || 'description' === type || 'prototype' === type) &&\n 'string' === typeof module\n ) {\n // it's straight HTML\n render = () => module;\n } else if ('data' === type && 'object' === typeof module) {\n // It's a data file (.json)\n render = this._modules[this._templates[key]];\n data = module;\n }\n\n // Only need render, as data will be left empty for static HTML\n if (render) {\n return { render, data };\n }\n\n return false;\n }\n\n /**\n * Replace all sections. For hot reloading use when the section template has changed.\n *\n * @param {object} replaceElements - The context (e.g. document) that you will query for the template ID to replace\n * @param {string} key - Module require path\n * @param {mixed} module - Module contents\n * @param {bool} cached - Whether or not to use cached values for module replacement\n * @param {object} filter - Filter for modules. Fields explained in the filterModules() function docs\n */\n loadModule(key, module, replaceElements, cached = false, filter = false) {\n let shouldLoad = true;\n let moduleMeta = false;\n\n // Check if we should load from internal module metadata cache\n if (cached) {\n moduleMeta = this.meta[key];\n } else {\n moduleMeta = this.meta[key] = this.getMetaFromPath(key, module);\n }\n\n if (moduleMeta) {\n if (filter) {\n shouldLoad = InsertNodes.filterModules(filter, moduleMeta);\n }\n\n if (shouldLoad) {\n this.replaceTemplate(moduleMeta, replaceElements);\n }\n }\n }\n\n /*\n * Helper function for inserting styleguide sections.\n *\n * Recurses over sorted styleguide sections and inserts a
to be used as a menu for each section\n */\n outputMenu(parent, el, sections = this._sections.sorted) {\n let templateId = null;\n let newEl = el;\n\n Object.keys(sections).forEach((section) => {\n const hasSubmenu = Object.keys(sections[section]).length;\n let menuTarget;\n let nextMenu;\n\n if (parent) {\n templateId = `${parent}-${section}`;\n } else {\n templateId = section;\n }\n\n if (newEl) {\n const title = this._sections\n .sectionsByURI[templateId] ?\n this._sections\n .sectionsByURI[templateId]\n .header :\n templateId;\n const sectionMenu = document.createElement('ul');\n const menuItem = document.createElement('li');\n const link = `${title}`;\n\n sectionMenu.classList.add('section-menu');\n menuItem.classList.add('section-menu__item');\n menuItem.innerHTML = link;\n\n // Check if this is a UL and, if not, create one\n if ('UL' !== newEl.tagName) {\n menuTarget = sectionMenu.cloneNode();\n newEl.appendChild(menuTarget);\n newEl = menuTarget;\n }\n\n // Has subsections\n if (hasSubmenu) {\n nextMenu = sectionMenu.cloneNode();\n nextMenu.classList.add('section-menu--submenu');\n menuItem.classList.add('section-menu__item--has-submenu');\n menuItem.appendChild(nextMenu);\n }\n\n newEl.appendChild(menuItem);\n\n if (hasSubmenu) {\n this.outputMenu(\n templateId,\n nextMenu,\n sections[section]\n );\n }\n }\n });\n }\n\n /**\n * Helper function for inserting styleguide sections.\n *\n * Recurses over sorted styleguide sections and inserts a tag with [huron-id] equal to the section template name.\n */\n outputSections(parent, el, sections = this._sections.sorted) {\n let templateId = null;\n let placeholder = null;\n\n Object.keys(sections).forEach((section) => {\n let istopLevel = false;\n let topLevelWrapper = null;\n let topLevelSection = null;\n let insertionEl = el;\n\n // Generate section ID and check if it is top-level\n if (parent) {\n templateId = `${parent}-${section}`;\n } else {\n templateId = section;\n istopLevel = true;\n }\n\n if (el) {\n // Generate huron placeholder for this section\n placeholder = document.createElement('div');\n placeholder.dataset.huronId = templateId;\n placeholder.dataset.huronType = 'section';\n\n if (istopLevel) {\n // Generate wrapper to contain top-level section and all subsections underneath it\n topLevelWrapper = document.createElement('div');\n topLevelWrapper.classList.add('section--top-level__wrapper');\n\n // Generate wrapper for top-level section\n topLevelSection = document.createElement('div');\n topLevelSection.classList.add('section', 'section--top-level');\n\n // Append wrappers to huron-sections element\n topLevelSection.appendChild(placeholder);\n topLevelWrapper.appendChild(topLevelSection);\n el.appendChild(topLevelWrapper);\n insertionEl = topLevelWrapper;\n } else {\n // If this is not top-level, append placeholder\n el.appendChild(placeholder);\n }\n }\n\n // Recursively call this function to insert other sections\n if (Object.keys(sections[section]).length && placeholder) {\n this.outputSections(\n templateId,\n insertionEl,\n sections[section]\n );\n }\n });\n }\n\n /**\n * Regenerate module meta cache\n */\n regenCache() {\n Object.keys(this._modules).forEach((moduleKey) => {\n this.meta[moduleKey] = this.getMetaFromPath(\n moduleKey, this._modules[moduleKey]\n );\n });\n }\n\n /**\n * Recursively remove old tags\n *\n * @param {string} hash - hash of module for which we need to remove old tags\n * @param {object} tag - tag to start our search with\n * (usually the tag immediately preceding the current placeholder)\n */\n removeOldTags(hash, tag) {\n if (tag) {\n const parentHash = InsertNodes.getDataAttribute(tag, 'parent-hash');\n const selfHash = InsertNodes.getDataAttribute(tag, 'self-hash');\n\n if (parentHash === hash && selfHash !== hash) {\n // This is a child of the current module,\n // so remove it and its children (if applicable)\n const childrenHash = selfHash;\n let nextTag = tag.previousSibling;\n\n if (childrenHash) {\n this.removeOldTags(childrenHash, nextTag);\n // Reset nextTag if we removed a child\n nextTag = tag.previousSibling;\n }\n\n tag.parentNode.removeChild(tag);\n this.removeOldTags(hash, nextTag);\n }\n }\n }\n\n /**\n * Replace a single template marker with template content.\n *\n * @param {object} replaceElements - Array of elements to check for Huron placeholders\n * @param {object} meta - Module metadata\n */\n replaceTemplate(meta, replaceElements) {\n const type = this.validateType(meta.type);\n const tags = [];\n let replace = replaceElements;\n let hasStyleguideHelpers = false;\n\n if (! replace) {\n replace = document.querySelectorAll(\n '[data-huron-id][data-huron-type]'\n );\n }\n\n if (type) {\n replace.forEach((tag) => {\n const tagType = InsertNodes.getDataAttribute(tag, 'huron-type');\n const tagId = InsertNodes.getDataAttribute(tag, 'huron-id');\n\n if (tagId === meta.id && tagType === type) {\n tags.push(tag);\n }\n });\n\n if (tags && tags.length && meta.render) {\n tags.forEach((currentTag) => {\n const modifiedPlaceholder = currentTag;\n const modifier = InsertNodes\n .getDataAttribute(modifiedPlaceholder, 'huron-modifier');\n const parent = modifiedPlaceholder.parentNode;\n const rendered = InsertNodes.applyModifier(modifier, meta);\n const renderedTemplate = InsertNodes.convertToElement(rendered)\n .querySelector('template');\n let renderedContents = null;\n\n // Remove existing module tags\n this.removeOldTags(meta.hash, modifiedPlaceholder.previousSibling);\n\n // Get the contents of the rendered template\n renderedContents = [\n ...renderedTemplate.content.children,\n ];\n\n // Insert each tag of the template contents before placeholder\n renderedContents.forEach((element) => {\n const newEl = element;\n\n if (1 === newEl.nodeType) {\n newEl.dataset.parentHash = meta.hash;\n hasStyleguideHelpers = ! hasStyleguideHelpers ?\n InsertNodes.isSectionHelper(newEl, meta) :\n hasStyleguideHelpers;\n\n parent.insertBefore(newEl, modifiedPlaceholder);\n }\n });\n\n // Add module hash to this placeholder\n modifiedPlaceholder.dataset.selfHash = meta.hash;\n\n // Hide the placeholder\n modifiedPlaceholder.style.display = 'none';\n\n // Recursively load modules, excluding the current one\n this.cycleModules(renderedContents, {\n property: 'key',\n values: [meta.key, this._sectionTemplatePath],\n include: false,\n });\n\n if (hasStyleguideHelpers) {\n this.cycleStyleguide();\n }\n });\n }\n } else {\n console.warn( // eslint-disable-line no-console\n `Could not render module\n section: ${meta.id}\n type: ${meta.type}`\n );\n }\n }\n\n /**\n * Verify specified element is using an acceptable huron type\n *\n * @param {string} type - type of partial (template, data, description, section or prototype )\n * @return {string} type - huron type or 'template' if invalid\n */\n validateType(type) {\n if ('data' === type) {\n return 'template';\n }\n\n if (! this._types.includes(type)) {\n return false;\n }\n\n return type;\n }\n\n /*\n * Set new modules object\n */\n set modules(modules) {\n this._modules = modules;\n this._moduleIds = Object.keys(modules);\n }\n\n /*\n * Set store\n */\n set store(store) {\n this._store = store;\n this._config = store.config;\n this._sections = store.sections;\n this._templates = store.templates;\n this._prototypes = store.prototypes;\n this._types = store.types;\n this._sectionTemplatePath = store.sectionTemplatePath;\n }\n}\n/* eslint-enable no-underscore-dangle */\n\n// Create a new instance of the InsertNodes class\n/*eslint-disable*/\n// Create object for modifiying the templates on the page and\n// initial first templates.\nconst insert = new InsertNodes(modules, store);\n/*eslint-enable*/\n"]}
\ No newline at end of file
diff --git a/package.json b/package.json
index 4cfc155..29863f8 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "huron",
"description": "An in-browser prototyping tool built on top of webpack and kss-node",
"author": "Alley Interactive",
- "version": "2.2.0",
+ "version": "2.2.1",
"license": "GPL-2.0",
"repository": {
"type": "git",
@@ -11,11 +11,14 @@
"scripts": {
"doc": "./node_modules/.bin/jsdoc src -r -c ./config/jsdoc.json",
"help": "./node_modules/.bin/babel-node src/cli/huron.js -h",
- "dev-cli": "webpack --config config/webpack-node.config.js -d --watch --progress --env.process=dev",
- "dev-web": "babel src/web -d dist/web -w --source-maps",
+ "dev-cli": "BABEL_ENV=cli webpack --config config/webpack-node.config.js -d --watch --progress --env.process=dev",
+ "build-cli": "BABEL_ENV=cli webpack --config \"config/webpack-node.config.js\" --env.process=build",
+ "dev-web": "BABEL_ENV=browser babel src/web -d dist/web -w --source-maps",
+ "build-web": "BABEL_ENV=browser babel src/web -d dist/web --source-maps",
"prebuild": "eslint -c config/.eslintrc src/**",
- "build": "webpack --config \"config/webpack-node.config.js\" --env.process=build && babel src/web -d dist/web --source-maps && jest",
+ "build": "npm run build-cli && npm run test:once && npm run build-web",
"postbuild": "bin/postbuild.js",
+ "test:once": "jest",
"test": "jest --watch"
},
"bin": {
@@ -34,7 +37,7 @@
"fs-extra": "^0.30.0",
"gaze": "^0.5.2",
"handlebars": "^4.0.6",
- "handlebars-template-loader": "^0.7.0",
+ "handlebars-loader": "^1.5.0",
"html-loader": "^0.4.3",
"html-webpack-plugin": "^2.28.0",
"immutable": "^3.8.1",
@@ -45,8 +48,8 @@
"webpack-dev-server": "^2.2.0"
},
"devDependencies": {
- "babel-cli": "^6.10.1",
- "babel-core": "^6.9.1",
+ "babel-cli": "^6.24.0",
+ "babel-core": "^6.25.0",
"babel-jest": "^20.0.3",
"babel-loader": "^6.2.10",
"babel-preset-env": "^1.1.8",
diff --git a/src/cli/actions.js b/src/cli/actions.js
index 79abb3a..3d85e19 100644
--- a/src/cli/actions.js
+++ b/src/cli/actions.js
@@ -74,7 +74,7 @@ export function updateFile(filepath, store) {
let field;
let section;
- if (- 1 !== filepath.indexOf(huron.get('sectionTemplate'))) {
+ if (filepath.includes(huron.get('sectionTemplate'))) {
return utils.writeSectionTemplate(filepath, store);
}
diff --git a/src/cli/generate-config.js b/src/cli/generate-config.js
index e234c9b..33d02ba 100644
--- a/src/cli/generate-config.js
+++ b/src/cli/generate-config.js
@@ -1,5 +1,4 @@
/** @module cli/generate-config */
-
import program from './parse-args';
import requireExternal from './require-external';
@@ -9,10 +8,11 @@ const url = require('url');
const fs = require('fs-extra');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
-const defaultConfig = require('../default-config/webpack.config');
+const defaultWebpack = require('../default-config/webpack.config');
const defaultHuron = require('../default-config/huron.config');
// Require configs passed in by user from CLI
+let defaultConfig = false;
const localConfigPath = ! path.isAbsolute(program.webpackConfig) ?
path.join(cwd, program.webpackConfig) :
program.webpackConfig;
@@ -43,16 +43,15 @@ export default function generateConfig() {
newHuron = newHuron(program.env);
}
+ // Merge huron defaults with user settings
newHuron = Object.assign({}, defaultHuron, newHuron);
+ // Use user huron config to modify webpack defaults
+ defaultConfig = defaultWebpack(newHuron);
// Set ouput options
newConfig.output = Object.assign({}, defaultConfig.output, newConfig.output);
- newConfig.output.path = path.resolve(cwd, newHuron.root);
- if (! program.production) {
- newConfig.output.publicPath = `http://localhost:${newHuron.port}/${newHuron.root}`;
- } else {
- newConfig.output.publicPath = '';
- }
+ newConfig.output.path = defaultConfig.output.path;
+ newConfig.output.publicPath = defaultConfig.output.publicPath;
// configure entries
newConfig = configureEntries(newHuron, newConfig);
@@ -143,19 +142,21 @@ function configureLoaders(huron, config) {
const templatesLoader = huron.templates.rule || {};
const newConfig = config;
- templatesLoader.include = [path.join(cwd, huron.root)];
+ // Make sure we're only using templates loader for files in huron root
+ templatesLoader.include = [path.join(cwd, huron.root, huron.output)];
+
+ // Normalize module and module.rules
newConfig.module = newConfig.module || {};
newConfig.module.rules = newConfig.module.rules ||
newConfig.module.loaders ||
[];
- newConfig.module.rules.push(
- {
- test: /\.html$/,
- use: 'html-loader',
- include: [path.join(cwd, huron.root)],
- },
- templatesLoader
- );
+
+ // Add default loaders
+ newConfig.module.rules = defaultConfig.module.rules
+ .concat(
+ newConfig.module.rules,
+ templatesLoader
+ );
return newConfig;
}
@@ -169,12 +170,12 @@ function configureLoaders(huron, config) {
*/
function configurePrototypes(huron, config) {
const wrapperTemplate = fs.readFileSync(
- path.join(__dirname, '../../templates/prototype-template.ejs'),
+ path.join(__dirname, '../../templates/prototype-template.hbs'),
'utf8'
);
const defaultHTMLPluginOptions = {
- title: '',
+ title: 'Huron',
window: huron.window,
js: [],
css: [],
@@ -182,7 +183,7 @@ function configurePrototypes(huron, config) {
template: path.join(
cwd,
huron.root,
- 'huron-assets/prototype-template.ejs'
+ 'huron-assets/prototype-template.hbs'
),
inject: false,
chunks: [huron.entry],
@@ -191,7 +192,7 @@ function configurePrototypes(huron, config) {
// Write prototype template file for HTML webpack plugin
fs.outputFileSync(
- path.join(cwd, huron.root, 'huron-assets/prototype-template.ejs'),
+ path.join(cwd, huron.root, 'huron-assets/prototype-template.hbs'),
wrapperTemplate
);
diff --git a/src/cli/require-templates.js b/src/cli/require-templates.js
index 689fafa..6c9cd70 100644
--- a/src/cli/require-templates.js
+++ b/src/cli/require-templates.js
@@ -26,17 +26,21 @@ export const requireTemplates = function requireTemplates(store) {
}$`);
const requirePath = `'../${huron.get('output')}'`;
- // Initialize templates, js, css and HMR acceptance logic
+ // Initialize templates, js, css and Hot Module Replacement acceptance logic
const prepend = `
var store = require('./huron-store.js');
+var sectionTemplate = require('./section.hbs');
var assets = require.context(${requirePath}, true, ${requireRegex});
var modules = {};
+modules['${store.get('sectionTemplatePath')}'] = sectionTemplate;
+
assets.keys().forEach(function(key) {
modules[key] = assets(key);
});
if (module.hot) {
+ // Hot Module Replacement for huron components (json, hbs, html)
module.hot.accept(
assets.id,
() => {
@@ -62,6 +66,21 @@ if (module.hot) {
}
);
+ // Hot Module Replacement for sections template
+ module.hot.accept(
+ './section.hbs',
+ () => {
+ var newSectionTemplate = require('./section.hbs');
+ modules['${store.get('sectionTemplatePath')}'] = newSectionTemplate;
+ hotReplace(
+ './huron-assets/section.hbs',
+ newSectionTemplate,
+ modules
+ );
+ }
+ );
+
+ // Hot Module Replacement for data store
module.hot.accept(
'./huron-store.js',
() => {
diff --git a/src/cli/utils.js b/src/cli/utils.js
index ecd9195..89d36e1 100644
--- a/src/cli/utils.js
+++ b/src/cli/utils.js
@@ -249,11 +249,10 @@ export function removeFile(id, type, filepath, store) {
export function writeSectionTemplate(filepath, store) {
const huron = store.get('config');
const sectionTemplate = wrapMarkup(fs.readFileSync(filepath, 'utf8'));
- const componentPath = './huron-sections/sections.hbs';
+ const componentPath = './huron-assets/section.hbs';
const output = path.join(
cwd,
huron.get('root'),
- huron.get('output'),
componentPath
);
diff --git a/src/default-config/webpack.config.js b/src/default-config/webpack.config.js
index 0378fd4..e0fee2f 100644
--- a/src/default-config/webpack.config.js
+++ b/src/default-config/webpack.config.js
@@ -1,46 +1,60 @@
+import program from '../cli/parse-args';
+
const webpack = require('webpack');
const path = require('path');
-module.exports = {
- entry: {},
- output: {
- // path: [huron root directory],
- filename: '[name].js',
- chunkFilename: '[name].chunk.min.js',
- },
- plugins: [
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NamedModulesPlugin(),
- ],
- resolve: {
- modulesDirectories: [
- path.resolve(__dirname, '../src/js'),
- ],
- },
- resolveLoader: {
- modulesDirectories: [
- 'web_loaders',
- 'web_modules',
- 'node_loaders',
- 'node_modules',
- path.resolve(__dirname, '../node_modules'),
+module.exports = (huron) => {
+ const cwd = process.cwd();
+
+ return {
+ entry: {},
+ output: {
+ path: path.join(cwd, huron.root),
+ publicPath: program.production ? '' :
+ `http://localhost:${huron.port}/${huron.root}`,
+ filename: '[name].js',
+ chunkFilename: '[name].chunk.min.js',
+ },
+ plugins: [
+ new webpack.HotModuleReplacementPlugin(),
+ new webpack.NamedModulesPlugin(),
],
- },
- module: {
- rules: [
- {
- test: /\.html?$/,
- use: [
- {
- loader: 'dom-loader',
+ resolve: {
+ modulesDirectories: [
+ path.resolve(__dirname, '../src/js'),
+ ],
+ },
+ resolveLoader: {
+ modulesDirectories: [
+ 'web_loaders',
+ 'web_modules',
+ 'node_loaders',
+ 'node_modules',
+ path.resolve(__dirname, '../node_modules'),
+ ],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.html$/,
+ include: [path.join(cwd, huron.root, huron.output)],
+ use: 'html-loader',
+ },
+ {
+ test: /\.(hbs|handlebars)$/,
+ include: [path.join(cwd, huron.root, 'huron-assets')],
+ use: {
+ loader: 'handlebars-loader',
options: {
- tag: 'dom-module',
+ helperDirs: path.join(
+ __dirname,
+ '../../',
+ 'templates/handlebars-helpers'
+ ),
},
},
- 'html-loader',
- ],
- // include: ['path/to/templates']
- },
- ],
- },
+ },
+ ],
+ },
+ };
};
diff --git a/templates/README.md b/templates/README.md
index ddc9339..b3e06e0 100644
--- a/templates/README.md
+++ b/templates/README.md
@@ -3,6 +3,6 @@
This directory contains default layout templates for styleguide [sections](./sections.hbs) and [prototype documents](./prototype-template.ejs). You may override each of these with your own markup. Before you do so, however, it's advised you take a look at the existing templates first.
* Styleguide section template: add a path to your own Handlebars template using the Huron `sectionTemplate` configuration field.
-* Prototype document template: in your Huron `prototypes` configuration array, supply a configuration object for one or more of your prototypes and include a `template` field in that object. This will override the `template` field of the HTML webpack plugin and allow you to supply a custom EJS template. NOTE: At some point we will provide a method of overriding this template globally, for all prototypes.
+* Prototype document template: in your Huron `prototypes` configuration array, supply a configuration object for one or more of your prototypes and include a `template` field in that object. This will override the `template` field of the HTML webpack plugin and allow you to supply a custom template. By default, HTML webpack plugin uses EJS for templates. However, for Huron you may also supply a template in the same language as your prototype partials.
* [EJS syntax](http://www.embeddedjs.com/)
- * [HTML webpack plugin templating instructions](https://github.com/ampedandwired/html-webpack-plugin)
\ No newline at end of file
+ * [HTML webpack plugin documentation](https://github.com/ampedandwired/html-webpack-plugin)
\ No newline at end of file
diff --git a/templates/handlebars-helpers/toJSON.js b/templates/handlebars-helpers/toJSON.js
new file mode 100644
index 0000000..bb98b97
--- /dev/null
+++ b/templates/handlebars-helpers/toJSON.js
@@ -0,0 +1,8 @@
+const Handlebars = require('handlebars');
+
+/**
+ * Convert object to JSON in a handlebars template
+ */
+module.exports = function toJSON(object) {
+ return new Handlebars.SafeString(JSON.stringify(object))
+};
diff --git a/templates/prototype-template.ejs b/templates/prototype-template.ejs
deleted file mode 100644
index 218dc1f..0000000
--- a/templates/prototype-template.ejs
+++ /dev/null
@@ -1,50 +0,0 @@
-
- manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>>
-
-
- <%= htmlWebpackPlugin.options.title || 'Huron' %> prototype
- <% if (htmlWebpackPlugin.files.favicon) { %>
-
- <% } %>
- <% for (var script in htmlWebpackPlugin.options.js) { %>
-
- <% } %>
- <% for (var stylesheet in htmlWebpackPlugin.options.css) { %>
-
- <% } %>
-
- <% for (var css in htmlWebpackPlugin.files.css) { %>
-
- <% } %>
- <% if (htmlWebpackPlugin.options.window) { %>
-
- <% } %>
-
-
-<% if (htmlWebpackPlugin.options.unsupportedBrowser) { %>
-
-
- Sorry, your browser is not supported. Please upgrade to
- the latest version or switch your browser to use this site.
- See outdatedbrowser.com
- for options.
-
-<% } %>
-<% if (htmlWebpackPlugin.options.appMountId) { %>
-
-<% } %>
-<% if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) { %>
- <% for (var index in htmlWebpackPlugin.options.appMountIds) { %>
-
- <% } %>
-<% } %>
-
-<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
-
-<% } %>
-
-
\ No newline at end of file
diff --git a/templates/prototype-template.hbs b/templates/prototype-template.hbs
new file mode 100644
index 0000000..5cf360a
--- /dev/null
+++ b/templates/prototype-template.hbs
@@ -0,0 +1,33 @@
+
+
+
+
+ {{htmlWebpackPlugin.options.title}} prototype
+ {{#if htmlWebpackPlugin.files.favicon}}
+
+ {{/if}}
+ {{#each htmlWebpackPlugin.options.css as |stylesheet|}}
+
+ {{/each}}
+
+ {{#each htmlWebpackPlugin.files.css as |css|}}
+
+ {{/each}}
+ {{#if htmlWebpackPlugin.options.window}}
+
+ {{/if}}
+
+
+
+{{#each htmlWebpackPlugin.options.js as |script|}}
+
+{{/each}}
+{{#each htmlWebpackPlugin.files.chunks as |chunk|}}
+
+{{/each}}
+
+
\ No newline at end of file