diff --git a/README.md b/README.md index 2180918..ecb325c 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ KSS is a documentation syntax and styleguide generator. All documentation should } ``` -* **Styleguide reference** - This is a required field, and must be written in the format `Styleguide [styleguide-section].[styleguide-subsection]`. You may have as many subsections as you like. You'll use this section reference when inserting markup in your prototypes by converting all `.` separators to `-`, creating a URI-like structure. We'll discuss this further in the next section. +* **Styleguide reference** - This is a required field, and must be written in the format `Styleguide [styleguide-section].[styleguide-subsection]`. You may have as many subsections as you like. You'll use this section reference when inserting markup in your prototypes by converting all `.` separators to `-`, creating a URI-like structure. For example, `Styleguide search-form.header` can be inserted via `data-huron-id="search-form-header"` We'll discuss this further in the next section. * _NOTE: As of now, Huron only supports one KSS documentation block per file, meaning it's heavily geared toward CSS preprocessors like SASS or LESS. This is an issue on our radar, however, and will be implemented at some point._ ## Writing prototypes diff --git a/dist/cli/index.js b/dist/cli/index.js index 419c75a..54cb1e7 100644 --- a/dist/cli/index.js +++ b/dist/cli/index.js @@ -380,12 +380,16 @@ function matchKssDir(filepath, huron) { function mergeClassnameJSON(directory) { let files; + // If no config is provided, return immediately + if (!directory) { + return {}; + } + // Try to read through classnames directory try { files = _fsExtra2.default.readdirSync(directory); } catch (e) { console.warn(_chalk2.default.red(e)); - return {}; } // Merge classname json files @@ -399,7 +403,6 @@ function mergeClassnameJSON(directory) { classNames = JSON.parse(contents); } catch (e) { console.warn(_chalk2.default.red(e)); - return classNames; } } @@ -773,87 +776,87 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @global */ // Local imports -const store = (0, _actions.initFiles)(_fileWatcher2.default.watched(), _defaultStore.defaultStore); const huron = _defaultStore.defaultStore.get('config'); +let store = (0, _actions.initFiles)(_fileWatcher2.default.watched(), _defaultStore.defaultStore); (0, _requireTemplates.requireTemplates)(store); (0, _requireTemplates.writeStore)(store); -if (!_parseArgs2.default.production) { - /** @module cli/gaze */ - let newStore = store; +// If building for production, close gaze and exit process once initFiles is done. +if (_parseArgs2.default.production) { + _fileWatcher2.default.close(); + process.exit(); +} - _fileWatcher2.default.on('all', (event, filepath) => { - newStore = (0, _actions.updateClassNames)(filepath, newStore); - (0, _requireTemplates.writeStore)(newStore); - }); +/** @module cli/gaze */ +_fileWatcher2.default.on('all', (event, filepath) => { + store = (0, _actions.updateClassNames)(filepath, store); + (0, _requireTemplates.writeStore)(store); +}); - /** - * Anonymous handler for Gaze 'changed' event indicating a file has changed - * - * @callback changed - * @listens gaze:changed - * @param {string} filepath - absolute path of changed file - */ - _fileWatcher2.default.on('changed', filepath => { - if ((0, _utils.matchKssDir)(filepath, huron)) { - newStore = (0, _actions.updateFile)(filepath, newStore); - } +/** + * Anonymous handler for Gaze 'changed' event indicating a file has changed + * + * @callback changed + * @listens gaze:changed + * @param {string} filepath - absolute path of changed file + */ +_fileWatcher2.default.on('changed', filepath => { + if ((0, _utils.matchKssDir)(filepath, huron)) { + store = (0, _actions.updateFile)(filepath, store); + } - console.log(_chalk2.default.green(`${filepath} updated!`)); - }); + console.log(_chalk2.default.green(`${filepath} updated!`)); +}); - /** - * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories - * - * @callback added - * @listens gaze:added - * @param {string} filepath - absolute path of changed file - */ - _fileWatcher2.default.on('added', filepath => { - if ((0, _utils.matchKssDir)(filepath, huron)) { - newStore = (0, _actions.updateFile)(filepath, newStore); - (0, _requireTemplates.writeStore)(newStore); - } +/** + * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories + * + * @callback added + * @listens gaze:added + * @param {string} filepath - absolute path of changed file + */ +_fileWatcher2.default.on('added', filepath => { + if ((0, _utils.matchKssDir)(filepath, huron)) { + store = (0, _actions.updateFile)(filepath, store); + (0, _requireTemplates.writeStore)(store); + } - console.log(_chalk2.default.blue(`${filepath} added!`)); - }); + console.log(_chalk2.default.blue(`${filepath} added!`)); +}); - /** - * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed - * - * @callback renamed - * @listens gaze:renamed - * @param {string} filepath - absolute path of changed file - */ - _fileWatcher2.default.on('renamed', (newPath, oldPath) => { - if ((0, _utils.matchKssDir)(newPath, huron)) { - newStore = (0, _actions.deleteFile)(oldPath, newStore); - newStore = (0, _actions.updateFile)(newPath, newStore); - (0, _requireTemplates.writeStore)(newStore); - } +/** + * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed + * + * @callback renamed + * @listens gaze:renamed + * @param {string} filepath - absolute path of changed file + */ +_fileWatcher2.default.on('renamed', (newPath, oldPath) => { + if ((0, _utils.matchKssDir)(newPath, huron)) { + store = (0, _actions.deleteFile)(oldPath, store); + store = (0, _actions.updateFile)(newPath, store); + (0, _requireTemplates.writeStore)(store); + } - console.log(_chalk2.default.blue(`${newPath} added!`)); - }); + console.log(_chalk2.default.blue(`${newPath} added!`)); +}); - /** - * Anonymous handler for Gaze 'deleted' event indicating a file has been removed - * - * @callback deleted - * @listens gaze:deleted - * @param {string} filepath - absolute path of changed file - */ - _fileWatcher2.default.on('deleted', filepath => { - if ((0, _utils.matchKssDir)(filepath, huron)) { - newStore = (0, _actions.deleteFile)(filepath, newStore); - (0, _requireTemplates.writeStore)(newStore); - } +/** + * Anonymous handler for Gaze 'deleted' event indicating a file has been removed + * + * @callback deleted + * @listens gaze:deleted + * @param {string} filepath - absolute path of changed file + */ +_fileWatcher2.default.on('deleted', filepath => { + if ((0, _utils.matchKssDir)(filepath, huron)) { + store = (0, _actions.deleteFile)(filepath, store); + (0, _requireTemplates.writeStore)(store); + } - console.log(_chalk2.default.red(`${filepath} deleted`)); - }); -} else { - _fileWatcher2.default.close(); -} + console.log(_chalk2.default.red(`${filepath} deleted`)); +}); // Start webpack or build for production (0, _server2.default)(_defaultStore.config); diff --git a/dist/cli/index.js.map b/dist/cli/index.js.map index 63d085f..4419cfe 100644 --- a/dist/cli/index.js.map +++ b/dist/cli/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["webpack:///webpack/bootstrap 03d06f67921b62e57b24","webpack:///external \"path\"","webpack:///src/cli/utils.js","webpack:///external \"chalk\"","webpack:///external \"fs-extra\"","webpack:///src/cli/parseArgs.js","webpack:///external \"webpack\"","webpack:///src/cli/defaultStore.js","webpack:///src/cli/handleTemplates.js","webpack:///src/cli/requireTemplates.js","webpack:///src/cli/index.js","webpack:///config/devServer.config.js","webpack:///src/cli/actions.js","webpack:///src/cli/fileWatcher.js","webpack:///src/cli/generateConfig.js","webpack:///src/cli/handleHTML.js","webpack:///src/cli/handleKSS.js","webpack:///src/cli/requireExternal.js","webpack:///src/cli/server.js","webpack:///src/defaultConfig/huron.config.js","webpack:///src/defaultConfig/webpack.config.js","webpack:///./templates/hotTemplate.js","webpack:///external \"commander\"","webpack:///external \"gaze\"","webpack:///external \"html-webpack-plugin\"","webpack:///external \"immutable\"","webpack:///external \"kss\"","webpack:///external \"lodash/isEqual\"","webpack:///external \"opn\"","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 = 30);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 03d06f67921b62e57b24","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 0\n// module chunks = 0","/** @module cli/utilities */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\n\nconst cwd = process.cwd(); // Current working directory\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\\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 // 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\n if (kssMatch.length) {\n return kssMatch[0];\n }\n\n return false;\n}\n\n/**\n * Merge JSON files for css modules classnames in a provided directory\n *\n * @function mergeClassnameJSON\n * @param {string} directory - directory containing classname JSON files\n *\n * @return {object} classnamesMerged - merged classnames. contents of each JSON file is nested within\n * the returned object by filename. (e.g. article.json -> { article: {...json contents}})\n */\nexport function mergeClassnameJSON(directory) {\n let files;\n\n // Try to read through classnames directory\n try {\n files = fs.readdirSync(directory);\n } catch (e) {\n console.warn(chalk.red(e));\n return {};\n }\n\n // Merge classname json files\n const classNamesMerged = files.reduce((acc, file) => {\n const fileInfo = path.parse(file);\n let classNames = {};\n\n if ('.json' === fileInfo.ext) {\n try {\n const contents = fs.readFileSync(\n path.join(directory, file),\n 'utf8'\n );\n classNames = JSON.parse(contents);\n } catch (e) {\n console.warn(chalk.red(e));\n return classNames;\n }\n }\n\n return Object.assign({}, acc, { [fileInfo.name]: classNames });\n }, {});\n\n return classNamesMerged;\n}\n\n/**\n * Remove the trailing slash from a provided directory\n *\n * @function removeTrailingSlash\n * @param {string} directory - directory path\n * @return {string} directory - directory path with trailing slash removed\n */\nexport function removeTrailingSlash(directory) {\n if ('/' === directory.slice(-1)) {\n return directory.slice(0, -1);\n }\n\n return directory;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/utils.js","module.exports = require(\"chalk\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"chalk\"\n// module id = 2\n// module chunks = 0","module.exports = require(\"fs-extra\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"fs-extra\"\n// module id = 3\n// module chunks = 0","/** @module cli/parse-arguments */\n/* eslint-disable space-unary-ops */\n\nimport program from 'commander';\nimport path from 'path';\n\n// Requires\n/** @global */\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, '../defaultConfig/huron.config.js')\n )\n .option(\n '-w, --webpack-config [webpackConfig]',\n '[webpackConfig] for all webpack options',\n path.resolve(__dirname, '../defaultConfig/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\nexport default program;\n\n\n\n// WEBPACK FOOTER //\n// src/cli/parseArgs.js","module.exports = require(\"webpack\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack\"\n// module id = 5\n// module chunks = 0","import { Map } from 'immutable';\n\nimport generateConfig from './generateConfig';\nimport { mergeClassnameJSON } from './utils';\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 = [].concat(config.huron.kss);\n\n/* eslint-disable */\n/**\n * Initial structure for immutable data store\n *\n * @global\n */\nconst defaultStore = Map({\n types: [\n 'template',\n 'data',\n 'description',\n 'section',\n 'prototype',\n 'sections-template',\n ],\n config: Map(config.huron),\n classNames: mergeClassnameJSON(config.huron.classNames),\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 { defaultStore, config };\n\n\n\n// WEBPACK FOOTER //\n// src/cli/defaultStore.js","/** @module cli/template-handler */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\n\nimport * as utils from './utils';\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/handleTemplates.js","/** @module cli/require-templates */\nimport path from 'path';\nimport fs from 'fs-extra';\n\n// We need to prepend this to the browser script as a string but still want to transpile it,\n// hence loading it using `raw-loader` so we receive a string from webpack\n/* eslint-disable */\nimport hotTemplate from '!raw-loader!babel-loader!../../templates/hotTemplate';\n/* eslint-enable */\n\nconst cwd = process.cwd();\nconst huronScript = fs.readFileSync(\n path.join(__dirname, '../web/index.js'),\n 'utf8'\n);\n\n/**\n * Write code for requiring all generated huron assets\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 // These will be used to replace strings in the hotTemplate.\n // In order to accurately replace strings but still keep things parseable by eslint and babel,\n // each replaceable value should be referenced in `hotTemplate.js` under the `hotScope` object.\n // For example, if you need to replace a string with a value passed in from the CLI called `userVariable`,\n // you would reference that string in `hotTemplate.js` with `hotScope.userVariable`.\n const hotVariableScope = {\n sectionTemplatePath: `'${huron.get('sectionTemplate')}'`,\n requireRegex: new RegExp(`\\\\.html|\\\\.json|\\\\${\n huron.get('templates').extension\n }$`),\n requirePath: `'../${huron.get('output')}'`,\n };\n const hotTemplateTransformed = Object.keys(hotVariableScope)\n .reduce(\n (acc, curr) => acc.replace(\n new RegExp(`hotScope.${curr}`, 'g'),\n hotVariableScope[curr]\n ), hotTemplate\n );\n\n // Write the contents of this script.\n fs.outputFileSync(\n path.join(outputPath, 'index.js'),\n hotTemplateTransformed\n );\n fs.outputFileSync(\n path.join(outputPath, 'insertNodes.js'),\n huronScript\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, newStore = false) {\n const updatedStore = newStore || store;\n const huron = updatedStore.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n\n // Write updated data store\n fs.outputFileSync(\n path.join(outputPath, 'huron-store.js'),\n `module.exports = ${JSON.stringify(updatedStore.toJSON())}`\n );\n};\n\n\n\n\n// WEBPACK FOOTER //\n// src/cli/requireTemplates.js","// Local imports\nimport chalk from 'chalk';\n\nimport {\n initFiles,\n updateFile,\n deleteFile,\n updateClassNames,\n} from './actions';\nimport { requireTemplates, writeStore } from './requireTemplates';\nimport { matchKssDir } from './utils';\nimport program from './parseArgs';\nimport startWebpack from './server';\nimport { defaultStore, config } from './defaultStore';\nimport gaze from './fileWatcher';\n\n/**\n * Initialize data store with files from gaze and original data structure\n *\n * @global\n */\nconst store = initFiles(gaze.watched(), defaultStore);\nconst huron = defaultStore.get('config');\n\nrequireTemplates(store);\nwriteStore(store);\n\nif (!program.production) {\n /** @module cli/gaze */\n let newStore = store;\n\n gaze.on('all', (event, filepath) => {\n newStore = updateClassNames(filepath, newStore);\n writeStore(newStore);\n });\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 if (matchKssDir(filepath, huron)) {\n newStore = updateFile(filepath, newStore);\n }\n\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 if (matchKssDir(filepath, huron)) {\n newStore = updateFile(filepath, newStore);\n writeStore(newStore);\n }\n\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 if (matchKssDir(newPath, huron)) {\n newStore = deleteFile(oldPath, newStore);\n newStore = updateFile(newPath, newStore);\n writeStore(newStore);\n }\n\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 if (matchKssDir(filepath, huron)) {\n newStore = deleteFile(filepath, newStore);\n writeStore(newStore);\n }\n\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\n\n\n// WEBPACK FOOTER //\n// src/cli/index.js","export default (huron) => ({\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 overlay: true,\n publicPath: `http://localhost:${huron.port}/${huron.root}`,\n});\n\n\n\n// WEBPACK FOOTER //\n// config/devServer.config.js","/** @module cli/actions */\n\n// Imports\nimport path from 'path';\nimport chalk from 'chalk';\nimport isEqual from 'lodash/isEqual';\n\nimport {\n updateHTML,\n deleteHTML,\n updatePrototype,\n deletePrototype,\n} from './handleHTML';\nimport { updateTemplate, deleteTemplate } from './handleTemplates';\nimport { updateKSS, deleteKSS } from './handleKSS';\nimport * as utils from './utils';\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 * @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 const huron = store.get('config');\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\n // Only call update if data is a filepath and it's within the KSS source directory\n if (info.ext && !data.includes(huron.get('classNames'))) {\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 file.dir.includes('prototypes') &&\n file.name.includes('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 file.dir.includes('prototypes') &&\n file.name.includes('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 * Logic for updating localized classnames from CSS modules\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n *\n * @return void\n */\nexport function updateClassNames(filepath, store) {\n const classNamesPath = store.getIn(['config', 'classNames']);\n\n if (filepath.includes(classNamesPath)) {\n const oldClassnames = store.get('classNames');\n const newClassnames = utils.mergeClassnameJSON(classNamesPath);\n\n if (!isEqual(oldClassnames, newClassnames)) {\n return store.set('classNames', newClassnames);\n }\n }\n\n return store;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/actions.js","import { Gaze } from 'gaze';\nimport path from 'path';\n\nimport { removeTrailingSlash } from './utils';\nimport { defaultStore } from './defaultStore';\n\n/**\n * Huron configuration object\n *\n * @global\n */\nconst huron = defaultStore.get('config');\n\n/**\n * Available file extensions. Extensions should not include the leading '.'\n *\n * @global\n */\nexport const 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\nexport const watchedFiles = [];\n\n// Watch section template\nwatchedFiles.push(path.resolve(huron.get('sectionTemplate')));\n\n// Watch cssmodules classname files (if they exist)\nif (huron.get('classNames')) {\n watchedFiles.push(\n `${path.resolve(huron.get('classNames'))}/*.json`\n );\n}\n\n// Watch all provided kss directories\nhuron.get('kss').forEach((dir) => {\n watchedFiles.push(\n `${removeTrailingSlash(dir)}/**/*.+(${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(watchedFiles);\n\nexport default gaze;\n\n\n\n// WEBPACK FOOTER //\n// src/cli/fileWatcher.js","/** @module cli/generate-config */\nimport path from 'path';\nimport url from 'url';\nimport fs from 'fs-extra';\nimport webpack from 'webpack';\nimport HTMLWebpackPlugin from 'html-webpack-plugin';\n\nimport program from './parseArgs';\nimport requireExternal from './requireExternal';\nimport defaultWebpack from '../defaultConfig/webpack.config';\nimport defaultHuron from '../defaultConfig/huron.config';\n\nconst cwd = process.cwd();\n\n// Require configs passed in by user from CLI\nlet defaultConfig = false;\nconst localConfig = requireExternal(\n path.resolve(program.webpackConfig)\n);\nconst localHuron = requireExternal(\n path.resolve(program.huronConfig)\n);\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/index'),\n ].concat(entry);\n } else {\n newConfig.entry[huron.entry] = [\n path.join(cwd, huron.root, 'huron-assets/index'),\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/prototypeTemplate.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/prototypeTemplate.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/prototypeTemplate.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/generateConfig.js","/** @module cli/html-handler */\nimport path from 'path';\nimport fs from 'fs-extra';\n\nimport * as utils from './utils';\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/handleHTML.js","/** @module cli/kss-handler */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { parse } from 'kss';\nimport chalk from 'chalk';\n\nimport * as utils from './utils';\nimport { updateTemplate, deleteTemplate } from './handleTemplates';\nimport { writeStore } from './requireTemplates';\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/handleKSS.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/requireExternal.js","/** @module cli/webpack-server */\nimport webpack from 'webpack';\nimport WebpackDevServer from 'webpack-dev-server';\nimport chalk from 'chalk';\nimport open from 'opn';\n\nimport createDevServerConfig from '../../config/devServer.config';\nimport program from './parseArgs';\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, createDevServerConfig(huron));\n const prototypeName = huron.prototypes[0].title || huron.prototypes[0];\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 open(`http://localhost:${huron.port}/${huron.root}/${prototypeName}.html`);\n return true;\n }\n );\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/server.js","import path from 'path';\n\nexport default {\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 classNames: false,\n templates: {\n rule: {\n test: /\\.(hbs|handlebars)$/,\n use: 'handlebars-loader',\n },\n extension: '.hbs',\n },\n window: {},\n};\n\n\n\n// WEBPACK FOOTER //\n// src/defaultConfig/huron.config.js","import webpack from 'webpack';\nimport path from 'path';\n\nimport program from '../cli/parseArgs';\n\nexport default (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/handlebarsHelpers'\n )],\n },\n },\n },\n ],\n },\n };\n};\n\n\n\n// WEBPACK FOOTER //\n// src/defaultConfig/webpack.config.js","module.exports = \"'use strict';\\n\\nvar _huronStore = require('./huron-store');\\n\\nvar _huronStore2 = _interopRequireDefault(_huronStore);\\n\\nvar _insertNodes = require('./insertNodes');\\n\\nvar _insertNodes2 = _interopRequireDefault(_insertNodes);\\n\\nvar _section = require('./section.hbs');\\n\\nvar _section2 = _interopRequireDefault(_section);\\n\\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\\n\\n/* eslint-enable */\\n\\nconst assets = require.context(hotScope.requirePath, true, hotScope.requireRegex); /* globals hotScope */\\n\\n// NOTE: This is not a normal JS file! It is pulled in by the CLI as a string\\n// and prepended to the browser script after replacing anything referenced via `hotScope[variable]`\\n// with CLI arguments or config properties passed in by the user.\\n\\n/* eslint-disable */\\n\\nconst modules = {};\\n\\nmodules[hotScope.sectionTemplatePath] = _section2.default;\\n\\nassets.keys().forEach(key => {\\n modules[key] = assets(key);\\n});\\n\\nconst insert = new _insertNodes2.default(modules, _huronStore2.default);\\n\\nif (module.hot) {\\n // Hot Module Replacement for huron components (json, hbs, html)\\n module.hot.accept(assets.id, () => {\\n const newAssets = require.context(hotScope.requirePath, true, hotScope.requireRegex);\\n const newModules = newAssets.keys().map(key => [key, newAssets(key)]).filter(newModule => modules[newModule[0]] !== newModule[1]);\\n\\n updateStore(require('./huron-store.js')); // eslint-disable-line global-require, import/no-unresolved\\n newModules.forEach(module => {\\n modules[module[0]] = module[1];\\n hotReplace(module[0], module[1], modules);\\n });\\n });\\n\\n // Hot Module Replacement for sections template\\n module.hot.accept('./section.hbs', () => {\\n const newSectionTemplate = require('./section.hbs'); // eslint-disable-line global-require, import/no-unresolved\\n\\n modules[hotScope.sectionTemplatePath] = newSectionTemplate;\\n hotReplace('./huron-assets/section.hbs', newSectionTemplate, modules);\\n });\\n\\n // Hot Module Replacement for data store\\n module.hot.accept('./huron-store.js', () => {\\n updateStore(require('./huron-store.js')); // eslint-disable-line global-require, import/no-unresolved\\n });\\n}\\n\\nfunction hotReplace(key, module, newModules) {\\n insert.modules = newModules;\\n if (key === _huronStore2.default.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//////////////////\n// WEBPACK FOOTER\n// ./~/raw-loader!./~/babel-loader/lib!./templates/hotTemplate.js\n// module id = 20\n// module chunks = 0","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 21\n// module chunks = 0","module.exports = require(\"gaze\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"gaze\"\n// module id = 22\n// module chunks = 0","module.exports = require(\"html-webpack-plugin\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"html-webpack-plugin\"\n// module id = 23\n// module chunks = 0","module.exports = require(\"immutable\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"immutable\"\n// module id = 24\n// module chunks = 0","module.exports = require(\"kss\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kss\"\n// module id = 25\n// module chunks = 0","module.exports = require(\"lodash/isEqual\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"lodash/isEqual\"\n// module id = 26\n// module chunks = 0","module.exports = require(\"opn\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"opn\"\n// module id = 27\n// module chunks = 0","module.exports = require(\"url\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"url\"\n// module id = 28\n// module chunks = 0","module.exports = require(\"webpack-dev-server\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack-dev-server\"\n// module id = 29\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;;;;;;;;;;;;ACcA;AAkBA;AAqCA;AAqCA;AAcA;AAkBA;AAyBA;AA4CA;AAyCA;AAyBA;AAyBA;AAqBA;AA0CA;AACA;AAzWA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;;;;;;;AAPA;AAcA;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;;;;;;;;;AASA;AACA;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;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AC/WA;;;;;;ACAA;;;;;;;;;;;;;ACGA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;AACA;;;;;;AATA;AACA;AACA;AAaA;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;AACA;;;;;;;ACzDA;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;;;AAAA;AACA;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AAQA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AAnBA;AAqBA;AACA;AACA;AAAA;;;;;;;;;;;;ACzBA;AA0DA;AACA;AA1EA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AADA;AACA;;;;;AACA;;;;;;;;;AAPA;AAgBA;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;;;;;;;;;;;;;;AClGA;AACA;;;AAAA;AACA;;;AAIA;AACA;;;;;AAAA;AACA;AACA;AACA;AAPA;AACA;AACA;AANA;AACA;AAUA;AACA;AAIA;;;;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AALA;AAOA;AACA;AAOA;AACA;AAIA;AAIA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;;;;;;;;;ACxEA;AACA;;;AACA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;AAAA;AACA;;;;;AACA;;;;;AAhBA;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AAjBA;;;;;;;;;;;;ACwBA;AA8CA;AA+DA;AA0DA;AACA;AA7LA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;AADA;AACA;;;;;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA1BA;AACA;AA4BA;AACA;AACA;AACA;;;;;;;AA/DA;AACA;AACA;AAoEA;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;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;AC5MA;AACA;AAAA;AACA;;;AACA;AACA;AAAA;AACA;;;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;;;;;;;;ACtBA;AACA;AA9BA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;AAdA;AAeA;AACA;AAGA;AACA;AAGA;;;;;;;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;;;;;;;;;;;;AC7RA;AA0CA;AA+BA;AA+BA;AACA;AAvHA;AACA;;;AAAA;AACA;;;AACA;AACA;AADA;AACA;;;;;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AAhDA;AAyDA;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;;;AAAA;AACA;;;AAAA;AACA;AAAA;AACA;;;AACA;AACA;AADA;AACA;AAAA;AACA;AAAA;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;;;;;;;;;AAhFA;AACA;AAwFA;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;;;;;;;;;;;AC5aA;AAFA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACWA;AACA;AAhBA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;;;AAAA;AACA;;;;;AACA;;;;;;;AATA;AAgBA;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;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;AC1EA;AACA;;;;;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AALA;AAOA;AAxBA;;;;;;;;;;;;;ACFA;AACA;;;AAAA;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;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"index.js","sources":["webpack:///webpack/bootstrap b1fcba00da3785732403","webpack:///external \"path\"","webpack:///src/cli/utils.js","webpack:///external \"chalk\"","webpack:///external \"fs-extra\"","webpack:///src/cli/parseArgs.js","webpack:///external \"webpack\"","webpack:///src/cli/defaultStore.js","webpack:///src/cli/handleTemplates.js","webpack:///src/cli/requireTemplates.js","webpack:///src/cli/index.js","webpack:///config/devServer.config.js","webpack:///src/cli/actions.js","webpack:///src/cli/fileWatcher.js","webpack:///src/cli/generateConfig.js","webpack:///src/cli/handleHTML.js","webpack:///src/cli/handleKSS.js","webpack:///src/cli/requireExternal.js","webpack:///src/cli/server.js","webpack:///src/defaultConfig/huron.config.js","webpack:///src/defaultConfig/webpack.config.js","webpack:///./templates/hotTemplate.js","webpack:///external \"commander\"","webpack:///external \"gaze\"","webpack:///external \"html-webpack-plugin\"","webpack:///external \"immutable\"","webpack:///external \"kss\"","webpack:///external \"lodash/isEqual\"","webpack:///external \"opn\"","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 = 30);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap b1fcba00da3785732403","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 0\n// module chunks = 0","/** @module cli/utilities */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\n\nconst cwd = process.cwd(); // Current working directory\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\\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 // 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\n if (kssMatch.length) {\n return kssMatch[0];\n }\n\n return false;\n}\n\n/**\n * Merge JSON files for css modules classnames in a provided directory\n *\n * @function mergeClassnameJSON\n * @param {string} directory - directory containing classname JSON files\n *\n * @return {object} classnamesMerged - merged classnames. contents of each JSON file is nested within\n * the returned object by filename. (e.g. article.json -> { article: {...json contents}})\n */\nexport function mergeClassnameJSON(directory) {\n let files;\n\n // If no config is provided, return immediately\n if (!directory) {\n return {};\n }\n\n // Try to read through classnames directory\n try {\n files = fs.readdirSync(directory);\n } catch (e) {\n console.warn(chalk.red(e));\n }\n\n // Merge classname json files\n const classNamesMerged = files.reduce((acc, file) => {\n const fileInfo = path.parse(file);\n let classNames = {};\n\n if ('.json' === fileInfo.ext) {\n try {\n const contents = fs.readFileSync(\n path.join(directory, file),\n 'utf8'\n );\n classNames = JSON.parse(contents);\n } catch (e) {\n console.warn(chalk.red(e));\n }\n }\n\n return Object.assign({}, acc, { [fileInfo.name]: classNames });\n }, {});\n\n return classNamesMerged;\n}\n\n/**\n * Remove the trailing slash from a provided directory\n *\n * @function removeTrailingSlash\n * @param {string} directory - directory path\n * @return {string} directory - directory path with trailing slash removed\n */\nexport function removeTrailingSlash(directory) {\n if ('/' === directory.slice(-1)) {\n return directory.slice(0, -1);\n }\n\n return directory;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/utils.js","module.exports = require(\"chalk\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"chalk\"\n// module id = 2\n// module chunks = 0","module.exports = require(\"fs-extra\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"fs-extra\"\n// module id = 3\n// module chunks = 0","/** @module cli/parse-arguments */\n/* eslint-disable space-unary-ops */\n\nimport program from 'commander';\nimport path from 'path';\n\n// Requires\n/** @global */\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, '../defaultConfig/huron.config.js')\n )\n .option(\n '-w, --webpack-config [webpackConfig]',\n '[webpackConfig] for all webpack options',\n path.resolve(__dirname, '../defaultConfig/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\nexport default program;\n\n\n\n// WEBPACK FOOTER //\n// src/cli/parseArgs.js","module.exports = require(\"webpack\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack\"\n// module id = 5\n// module chunks = 0","import { Map } from 'immutable';\n\nimport generateConfig from './generateConfig';\nimport { mergeClassnameJSON } from './utils';\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 = [].concat(config.huron.kss);\n\n/* eslint-disable */\n/**\n * Initial structure for immutable data store\n *\n * @global\n */\nconst defaultStore = Map({\n types: [\n 'template',\n 'data',\n 'description',\n 'section',\n 'prototype',\n 'sections-template',\n ],\n config: Map(config.huron),\n classNames: mergeClassnameJSON(config.huron.classNames),\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 { defaultStore, config };\n\n\n\n// WEBPACK FOOTER //\n// src/cli/defaultStore.js","/** @module cli/template-handler */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\n\nimport * as utils from './utils';\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/handleTemplates.js","/** @module cli/require-templates */\nimport path from 'path';\nimport fs from 'fs-extra';\n\n// We need to prepend this to the browser script as a string but still want to transpile it,\n// hence loading it using `raw-loader` so we receive a string from webpack\n/* eslint-disable */\nimport hotTemplate from '!raw-loader!babel-loader!../../templates/hotTemplate';\n/* eslint-enable */\n\nconst cwd = process.cwd();\nconst huronScript = fs.readFileSync(\n path.join(__dirname, '../web/index.js'),\n 'utf8'\n);\n\n/**\n * Write code for requiring all generated huron assets\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 // These will be used to replace strings in the hotTemplate.\n // In order to accurately replace strings but still keep things parseable by eslint and babel,\n // each replaceable value should be referenced in `hotTemplate.js` under the `hotScope` object.\n // For example, if you need to replace a string with a value passed in from the CLI called `userVariable`,\n // you would reference that string in `hotTemplate.js` with `hotScope.userVariable`.\n const hotVariableScope = {\n sectionTemplatePath: `'${huron.get('sectionTemplate')}'`,\n requireRegex: new RegExp(`\\\\.html|\\\\.json|\\\\${\n huron.get('templates').extension\n }$`),\n requirePath: `'../${huron.get('output')}'`,\n };\n const hotTemplateTransformed = Object.keys(hotVariableScope)\n .reduce(\n (acc, curr) => acc.replace(\n new RegExp(`hotScope.${curr}`, 'g'),\n hotVariableScope[curr]\n ), hotTemplate\n );\n\n // Write the contents of this script.\n fs.outputFileSync(\n path.join(outputPath, 'index.js'),\n hotTemplateTransformed\n );\n fs.outputFileSync(\n path.join(outputPath, 'insertNodes.js'),\n huronScript\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, newStore = false) {\n const updatedStore = newStore || store;\n const huron = updatedStore.get('config');\n const outputPath = path.join(cwd, huron.get('root'), 'huron-assets');\n\n // Write updated data store\n fs.outputFileSync(\n path.join(outputPath, 'huron-store.js'),\n `module.exports = ${JSON.stringify(updatedStore.toJSON())}`\n );\n};\n\n\n\n\n// WEBPACK FOOTER //\n// src/cli/requireTemplates.js","// Local imports\nimport chalk from 'chalk';\n\nimport {\n initFiles,\n updateFile,\n deleteFile,\n updateClassNames,\n} from './actions';\nimport { requireTemplates, writeStore } from './requireTemplates';\nimport { matchKssDir } from './utils';\nimport program from './parseArgs';\nimport startWebpack from './server';\nimport { defaultStore, config } from './defaultStore';\nimport gaze from './fileWatcher';\n\n/**\n * Initialize data store with files from gaze and original data structure\n *\n * @global\n */\nconst huron = defaultStore.get('config');\nlet store = initFiles(gaze.watched(), defaultStore);\n\nrequireTemplates(store);\nwriteStore(store);\n\n// If building for production, close gaze and exit process once initFiles is done.\nif (program.production) {\n gaze.close();\n process.exit();\n}\n\n/** @module cli/gaze */\ngaze.on('all', (event, filepath) => {\n store = updateClassNames(filepath, store);\n writeStore(store);\n});\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 */\ngaze.on('changed', (filepath) => {\n if (matchKssDir(filepath, huron)) {\n store = updateFile(filepath, store);\n }\n\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 */\ngaze.on('added', (filepath) => {\n if (matchKssDir(filepath, huron)) {\n store = updateFile(filepath, store);\n writeStore(store);\n }\n\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 */\ngaze.on('renamed', (newPath, oldPath) => {\n if (matchKssDir(newPath, huron)) {\n store = deleteFile(oldPath, store);\n store = updateFile(newPath, store);\n writeStore(store);\n }\n\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 */\ngaze.on('deleted', (filepath) => {\n if (matchKssDir(filepath, huron)) {\n store = deleteFile(filepath, store);\n writeStore(store);\n }\n\n console.log(chalk.red(`${filepath} deleted`));\n});\n\n// Start webpack or build for production\nstartWebpack(config);\n\n\n\n// WEBPACK FOOTER //\n// src/cli/index.js","export default (huron) => ({\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 overlay: true,\n publicPath: `http://localhost:${huron.port}/${huron.root}`,\n});\n\n\n\n// WEBPACK FOOTER //\n// config/devServer.config.js","/** @module cli/actions */\n\n// Imports\nimport path from 'path';\nimport chalk from 'chalk';\nimport isEqual from 'lodash/isEqual';\n\nimport {\n updateHTML,\n deleteHTML,\n updatePrototype,\n deletePrototype,\n} from './handleHTML';\nimport { updateTemplate, deleteTemplate } from './handleTemplates';\nimport { updateKSS, deleteKSS } from './handleKSS';\nimport * as utils from './utils';\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 * @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 const huron = store.get('config');\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\n // Only call update if data is a filepath and it's within the KSS source directory\n if (info.ext && !data.includes(huron.get('classNames'))) {\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 file.dir.includes('prototypes') &&\n file.name.includes('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 file.dir.includes('prototypes') &&\n file.name.includes('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 * Logic for updating localized classnames from CSS modules\n *\n * @param {string} filepath - path to updated file. usually passed in from Gaze\n * @param {object} store - memory store\n *\n * @return void\n */\nexport function updateClassNames(filepath, store) {\n const classNamesPath = store.getIn(['config', 'classNames']);\n\n if (filepath.includes(classNamesPath)) {\n const oldClassnames = store.get('classNames');\n const newClassnames = utils.mergeClassnameJSON(classNamesPath);\n\n if (!isEqual(oldClassnames, newClassnames)) {\n return store.set('classNames', newClassnames);\n }\n }\n\n return store;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/actions.js","import { Gaze } from 'gaze';\nimport path from 'path';\n\nimport { removeTrailingSlash } from './utils';\nimport { defaultStore } from './defaultStore';\n\n/**\n * Huron configuration object\n *\n * @global\n */\nconst huron = defaultStore.get('config');\n\n/**\n * Available file extensions. Extensions should not include the leading '.'\n *\n * @global\n */\nexport const 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\nexport const watchedFiles = [];\n\n// Watch section template\nwatchedFiles.push(path.resolve(huron.get('sectionTemplate')));\n\n// Watch cssmodules classname files (if they exist)\nif (huron.get('classNames')) {\n watchedFiles.push(\n `${path.resolve(huron.get('classNames'))}/*.json`\n );\n}\n\n// Watch all provided kss directories\nhuron.get('kss').forEach((dir) => {\n watchedFiles.push(\n `${removeTrailingSlash(dir)}/**/*.+(${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(watchedFiles);\n\nexport default gaze;\n\n\n\n// WEBPACK FOOTER //\n// src/cli/fileWatcher.js","/** @module cli/generate-config */\nimport path from 'path';\nimport url from 'url';\nimport fs from 'fs-extra';\nimport webpack from 'webpack';\nimport HTMLWebpackPlugin from 'html-webpack-plugin';\n\nimport program from './parseArgs';\nimport requireExternal from './requireExternal';\nimport defaultWebpack from '../defaultConfig/webpack.config';\nimport defaultHuron from '../defaultConfig/huron.config';\n\nconst cwd = process.cwd();\n\n// Require configs passed in by user from CLI\nlet defaultConfig = false;\nconst localConfig = requireExternal(\n path.resolve(program.webpackConfig)\n);\nconst localHuron = requireExternal(\n path.resolve(program.huronConfig)\n);\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/index'),\n ].concat(entry);\n } else {\n newConfig.entry[huron.entry] = [\n path.join(cwd, huron.root, 'huron-assets/index'),\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/prototypeTemplate.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/prototypeTemplate.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/prototypeTemplate.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/generateConfig.js","/** @module cli/html-handler */\nimport path from 'path';\nimport fs from 'fs-extra';\n\nimport * as utils from './utils';\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/handleHTML.js","/** @module cli/kss-handler */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { parse } from 'kss';\nimport chalk from 'chalk';\n\nimport * as utils from './utils';\nimport { updateTemplate, deleteTemplate } from './handleTemplates';\nimport { writeStore } from './requireTemplates';\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/handleKSS.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/requireExternal.js","/** @module cli/webpack-server */\nimport webpack from 'webpack';\nimport WebpackDevServer from 'webpack-dev-server';\nimport chalk from 'chalk';\nimport open from 'opn';\n\nimport createDevServerConfig from '../../config/devServer.config';\nimport program from './parseArgs';\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, createDevServerConfig(huron));\n const prototypeName = huron.prototypes[0].title || huron.prototypes[0];\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 open(`http://localhost:${huron.port}/${huron.root}/${prototypeName}.html`);\n return true;\n }\n );\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// src/cli/server.js","import path from 'path';\n\nexport default {\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 classNames: false,\n templates: {\n rule: {\n test: /\\.(hbs|handlebars)$/,\n use: 'handlebars-loader',\n },\n extension: '.hbs',\n },\n window: {},\n};\n\n\n\n// WEBPACK FOOTER //\n// src/defaultConfig/huron.config.js","import webpack from 'webpack';\nimport path from 'path';\n\nimport program from '../cli/parseArgs';\n\nexport default (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/handlebarsHelpers'\n )],\n },\n },\n },\n ],\n },\n };\n};\n\n\n\n// WEBPACK FOOTER //\n// src/defaultConfig/webpack.config.js","module.exports = \"'use strict';\\n\\nvar _huronStore = require('./huron-store');\\n\\nvar _huronStore2 = _interopRequireDefault(_huronStore);\\n\\nvar _insertNodes = require('./insertNodes');\\n\\nvar _insertNodes2 = _interopRequireDefault(_insertNodes);\\n\\nvar _section = require('./section.hbs');\\n\\nvar _section2 = _interopRequireDefault(_section);\\n\\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\\n\\n/* eslint-enable */\\n\\nconst assets = require.context(hotScope.requirePath, true, hotScope.requireRegex); /* globals hotScope */\\n\\n// NOTE: This is not a normal JS file! It is pulled in by the CLI as a string\\n// and prepended to the browser script after replacing anything referenced via `hotScope[variable]`\\n// with CLI arguments or config properties passed in by the user.\\n\\n/* eslint-disable */\\n\\nconst modules = {};\\n\\nmodules[hotScope.sectionTemplatePath] = _section2.default;\\n\\nassets.keys().forEach(key => {\\n modules[key] = assets(key);\\n});\\n\\nconst insert = new _insertNodes2.default(modules, _huronStore2.default);\\n\\nif (module.hot) {\\n // Hot Module Replacement for huron components (json, hbs, html)\\n module.hot.accept(assets.id, () => {\\n const newAssets = require.context(hotScope.requirePath, true, hotScope.requireRegex);\\n const newModules = newAssets.keys().map(key => [key, newAssets(key)]).filter(newModule => modules[newModule[0]] !== newModule[1]);\\n\\n updateStore(require('./huron-store.js')); // eslint-disable-line global-require, import/no-unresolved\\n newModules.forEach(module => {\\n modules[module[0]] = module[1];\\n hotReplace(module[0], module[1], modules);\\n });\\n });\\n\\n // Hot Module Replacement for sections template\\n module.hot.accept('./section.hbs', () => {\\n const newSectionTemplate = require('./section.hbs'); // eslint-disable-line global-require, import/no-unresolved\\n\\n modules[hotScope.sectionTemplatePath] = newSectionTemplate;\\n hotReplace('./huron-assets/section.hbs', newSectionTemplate, modules);\\n });\\n\\n // Hot Module Replacement for data store\\n module.hot.accept('./huron-store.js', () => {\\n updateStore(require('./huron-store.js')); // eslint-disable-line global-require, import/no-unresolved\\n });\\n}\\n\\nfunction hotReplace(key, module, newModules) {\\n insert.modules = newModules;\\n if (key === _huronStore2.default.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//////////////////\n// WEBPACK FOOTER\n// ./~/raw-loader!./~/babel-loader/lib!./templates/hotTemplate.js\n// module id = 20\n// module chunks = 0","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 21\n// module chunks = 0","module.exports = require(\"gaze\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"gaze\"\n// module id = 22\n// module chunks = 0","module.exports = require(\"html-webpack-plugin\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"html-webpack-plugin\"\n// module id = 23\n// module chunks = 0","module.exports = require(\"immutable\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"immutable\"\n// module id = 24\n// module chunks = 0","module.exports = require(\"kss\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kss\"\n// module id = 25\n// module chunks = 0","module.exports = require(\"lodash/isEqual\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"lodash/isEqual\"\n// module id = 26\n// module chunks = 0","module.exports = require(\"opn\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"opn\"\n// module id = 27\n// module chunks = 0","module.exports = require(\"url\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"url\"\n// module id = 28\n// module chunks = 0","module.exports = require(\"webpack-dev-server\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"webpack-dev-server\"\n// module id = 29\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;;;;;;;;;;;;ACcA;AAkBA;AAqCA;AAqCA;AAcA;AAkBA;AAyBA;AA4CA;AAyCA;AAyBA;AAyBA;AAqBA;AA6CA;AACA;AA5WA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;;;;;;;AAPA;AAcA;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;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;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;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AClXA;;;;;;ACAA;;;;;;;;;;;;;ACGA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;AACA;;;;;;AATA;AACA;AACA;AAaA;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;AACA;;;;;;;ACzDA;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;;;AAAA;AACA;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AAQA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AAnBA;AAqBA;AACA;AACA;AAAA;;;;;;;;;;;;ACzBA;AA0DA;AACA;AA1EA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AADA;AACA;;;;;AACA;;;;;;;;;AAPA;AAgBA;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;;;;;;;;;;;;;;AClGA;AACA;;;AAAA;AACA;;;AAIA;AACA;;;;;AAAA;AACA;AACA;AACA;AAPA;AACA;AACA;AANA;AACA;AAUA;AACA;AAIA;;;;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AALA;AAOA;AACA;AAOA;AACA;AAIA;AAIA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;;;;;;;;;ACxEA;AACA;;;AACA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;AAAA;AACA;;;;;AACA;;;;;AAhBA;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AAjBA;;;;;;;;;;;;ACwBA;AA8CA;AA+DA;AA0DA;AACA;AA7LA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;AAKA;AACA;AAAA;AACA;AAAA;AACA;AADA;AACA;;;;;AACA;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA1BA;AACA;AA4BA;AACA;AACA;AACA;;;;;;;AA/DA;AACA;AACA;AAoEA;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;AACA;AACA;;;;;;;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;AC5MA;AACA;AAAA;AACA;;;AACA;AACA;AAAA;AACA;;;AACA;;;;;AAKA;AACA;AACA;;;;;AAKA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;;;;AAKA;AACA;AACA;;;;;;;;;;;;ACtBA;AACA;AA9BA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;;;AACA;AACA;AACA;AAdA;AAeA;AACA;AAGA;AACA;AAGA;;;;;;;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;;;;;;;;;;;;AC7RA;AA0CA;AA+BA;AA+BA;AACA;AAvHA;AACA;;;AAAA;AACA;;;AACA;AACA;AADA;AACA;;;;;AACA;;;;;;;;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;AAhDA;AAyDA;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;;;AAAA;AACA;;;AAAA;AACA;AAAA;AACA;;;AACA;AACA;AADA;AACA;AAAA;AACA;AAAA;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;;;;;;;;;AAhFA;AACA;AAwFA;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;;;;;;;;;;;AC5aA;AAFA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACWA;AACA;AAhBA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AAAA;AACA;;;AACA;AACA;;;AAAA;AACA;;;;;AACA;;;;;;;AATA;AAgBA;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;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;AC1EA;AACA;;;;;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AAIA;AALA;AAOA;AAxBA;;;;;;;;;;;;;ACFA;AACA;;;AAAA;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;;;;;;ACAA;;;;;;ACAA;;;;;;ACAA;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/package.json b/package.json index d754e35..7534da9 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.3.0-beta.5", + "version": "2.3.0-beta.6", "license": "GPL-2.0", "repository": { "type": "git", diff --git a/src/cli/index.js b/src/cli/index.js index f618b65..247142c 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -19,87 +19,87 @@ import gaze from './fileWatcher'; * * @global */ -const store = initFiles(gaze.watched(), defaultStore); const huron = defaultStore.get('config'); +let store = initFiles(gaze.watched(), defaultStore); requireTemplates(store); writeStore(store); -if (!program.production) { - /** @module cli/gaze */ - let newStore = store; +// If building for production, close gaze and exit process once initFiles is done. +if (program.production) { + gaze.close(); + process.exit(); +} - gaze.on('all', (event, filepath) => { - newStore = updateClassNames(filepath, newStore); - writeStore(newStore); - }); +/** @module cli/gaze */ +gaze.on('all', (event, filepath) => { + store = updateClassNames(filepath, store); + writeStore(store); +}); - /** - * Anonymous handler for Gaze 'changed' event indicating a file has changed - * - * @callback changed - * @listens gaze:changed - * @param {string} filepath - absolute path of changed file - */ - gaze.on('changed', (filepath) => { - if (matchKssDir(filepath, huron)) { - newStore = updateFile(filepath, newStore); - } +/** + * Anonymous handler for Gaze 'changed' event indicating a file has changed + * + * @callback changed + * @listens gaze:changed + * @param {string} filepath - absolute path of changed file + */ +gaze.on('changed', (filepath) => { + if (matchKssDir(filepath, huron)) { + store = updateFile(filepath, store); + } - console.log(chalk.green(`${filepath} updated!`)); - }); + console.log(chalk.green(`${filepath} updated!`)); +}); - /** - * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories - * - * @callback added - * @listens gaze:added - * @param {string} filepath - absolute path of changed file - */ - gaze.on('added', (filepath) => { - if (matchKssDir(filepath, huron)) { - newStore = updateFile(filepath, newStore); - writeStore(newStore); - } +/** + * Anonymous handler for Gaze 'added' event indicating a file has been added to the watched directories + * + * @callback added + * @listens gaze:added + * @param {string} filepath - absolute path of changed file + */ +gaze.on('added', (filepath) => { + if (matchKssDir(filepath, huron)) { + store = updateFile(filepath, store); + writeStore(store); + } - console.log(chalk.blue(`${filepath} added!`)); - }); + console.log(chalk.blue(`${filepath} added!`)); +}); - /** - * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed - * - * @callback renamed - * @listens gaze:renamed - * @param {string} filepath - absolute path of changed file - */ - gaze.on('renamed', (newPath, oldPath) => { - if (matchKssDir(newPath, huron)) { - newStore = deleteFile(oldPath, newStore); - newStore = updateFile(newPath, newStore); - writeStore(newStore); - } +/** + * Anonymous handler for Gaze 'renamed' event indicating a file has been renamed + * + * @callback renamed + * @listens gaze:renamed + * @param {string} filepath - absolute path of changed file + */ +gaze.on('renamed', (newPath, oldPath) => { + if (matchKssDir(newPath, huron)) { + store = deleteFile(oldPath, store); + store = updateFile(newPath, store); + writeStore(store); + } - console.log(chalk.blue(`${newPath} added!`)); - }); + console.log(chalk.blue(`${newPath} added!`)); +}); - /** - * Anonymous handler for Gaze 'deleted' event indicating a file has been removed - * - * @callback deleted - * @listens gaze:deleted - * @param {string} filepath - absolute path of changed file - */ - gaze.on('deleted', (filepath) => { - if (matchKssDir(filepath, huron)) { - newStore = deleteFile(filepath, newStore); - writeStore(newStore); - } +/** + * Anonymous handler for Gaze 'deleted' event indicating a file has been removed + * + * @callback deleted + * @listens gaze:deleted + * @param {string} filepath - absolute path of changed file + */ +gaze.on('deleted', (filepath) => { + if (matchKssDir(filepath, huron)) { + store = deleteFile(filepath, store); + writeStore(store); + } - console.log(chalk.red(`${filepath} deleted`)); - }); -} else { - gaze.close(); -} + console.log(chalk.red(`${filepath} deleted`)); +}); // Start webpack or build for production startWebpack(config); diff --git a/src/cli/utils.js b/src/cli/utils.js index 72903a8..9d80b29 100644 --- a/src/cli/utils.js +++ b/src/cli/utils.js @@ -320,12 +320,16 @@ export function matchKssDir(filepath, huron) { export function mergeClassnameJSON(directory) { let files; + // If no config is provided, return immediately + if (!directory) { + return {}; + } + // Try to read through classnames directory try { files = fs.readdirSync(directory); } catch (e) { console.warn(chalk.red(e)); - return {}; } // Merge classname json files @@ -342,7 +346,6 @@ export function mergeClassnameJSON(directory) { classNames = JSON.parse(contents); } catch (e) { console.warn(chalk.red(e)); - return classNames; } }