From 4419b13092e605a95ac0c54ffa21639aa36f4b82 Mon Sep 17 00:00:00 2001 From: marvinchin Date: Thu, 7 Mar 2019 16:12:55 +0800 Subject: [PATCH 1/3] Add prettier configs --- .eslintignore | 3 +- .eslintrc.js | 83 +++++++++++++++++++++++---------------------------- .prettierrc | 4 +++ package.json | 6 +++- 4 files changed, 47 insertions(+), 49 deletions(-) create mode 100644 .prettierrc diff --git a/.eslintignore b/.eslintignore index 31e0c6686b..84ed52a165 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,3 @@ *.min.* src/lib/markbind/src/lib/markdown-it/* - -!.eslintrc.js +.eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js index eef185144e..3fc5e1c991 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,55 +2,46 @@ /* eslint quotes: ["error", "double"] */ module.exports = { - "env": { - "node": true, - "es6": true, - "jest": true, + env: { + node: true, + es6: true, + jest: true, }, - "plugins": ["lodash"], - "extends": ["airbnb-base", "plugin:lodash/recommended"], - "rules": { - "array-bracket-newline": ["error", { "multiline": true }], - "func-names": "off", - "no-underscore-dangle": "off", - "function-paren-newline": "off", - "indent": [ - "error", - 2, - { - "CallExpression": { "arguments": "first" }, - "FunctionDeclaration": { "parameters": "first" }, - "FunctionExpression": { "parameters": "first" }, - }, - ], - "lodash/prefer-lodash-method": [0], - "lodash/prefer-noop": [0], - "max-len": ["error", { "code": 110 }], - "operator-linebreak": ["error", "before"], + plugins: ['lodash', 'prettier'], + extends: ['airbnb-base', 'plugin:lodash/recommended', 'prettier'], + rules: { + 'func-names': 'off', + 'function-paren-newline': 'off', + 'lodash/prefer-lodash-method': [0], + 'lodash/prefer-noop': [0], + 'max-len': ['error', { code: 110 }], + 'no-underscore-dangle': 'off', + 'prettier/prettier': 'error', // override airbnb-base dev dependencies, latest version does not white list __mocks__ - "import/no-extraneous-dependencies": [ - "error", { - "devDependencies": [ - "test/**", // tape, common npm pattern - "tests/**", // also common npm pattern - "spec/**", // mocha, rspec-like pattern - "**/__tests__/**", // jest pattern - "**/__mocks__/**", // jest pattern - "test.{js,jsx}", // repos with a single test file - "test-*.{js,jsx}", // repos with multiple top-level test files - "**/*.{test,spec}.{js,jsx}", // tests where the extension denotes that it is a test - "**/jest.config.js", // jest config - "**/webpack.config.js", // webpack config - "**/webpack.config.*.js", // webpack config - "**/rollup.config.*.js", // rollup config - "**/rollup.config.*.js", // rollup config - "**/gulpfile.js", // gulp config - "**/gulpfile.*.js", // gulp config - "**/Gruntfile{,.js}", // grunt config - "**/protractor.conf.js", // protractor config - "**/protractor.conf.*.js", // protractor config + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: [ + 'test/**', // tape, common npm pattern + 'tests/**', // also common npm pattern + 'spec/**', // mocha, rspec-like pattern + '**/__tests__/**', // jest pattern + '**/__mocks__/**', // jest pattern + 'test.{js,jsx}', // repos with a single test file + 'test-*.{js,jsx}', // repos with multiple top-level test files + '**/*.{test,spec}.{js,jsx}', // tests where the extension denotes that it is a test + '**/jest.config.js', // jest config + '**/webpack.config.js', // webpack config + '**/webpack.config.*.js', // webpack config + '**/rollup.config.*.js', // rollup config + '**/rollup.config.*.js', // rollup config + '**/gulpfile.js', // gulp config + '**/gulpfile.*.js', // gulp config + '**/Gruntfile{,.js}', // grunt config + '**/protractor.conf.js', // protractor config + '**/protractor.conf.*.js', // protractor config ], - "optionalDependencies": false, + optionalDependencies: false, }, ], }, diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..6e778b4fb9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "trailingComma": "all", + "singleQuote": true +} diff --git a/package.json b/package.json index 8450a96954..81be7027e5 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "url": "https://github.com/MarkBind/markbind.git" }, "scripts": { + "prettier": "./node_modules/.bin/prettier --write '**/*.js' '!**/*.min.*' '!src/lib/markbind/src/lib/markdown-it/**/*.js'", "lint": "./node_modules/.bin/eslint .", "pretest": "npm run lint", "pretestwin": "npm run lint", @@ -76,9 +77,12 @@ "diff": "^3.5.0", "eslint": "^4.16.0", "eslint-config-airbnb-base": "^12.1.0", + "eslint-config-prettier": "^4.1.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-lodash": "^2.6.1", + "eslint-plugin-prettier": "^3.0.1", "jest": "^22.4.3", - "memfs": "^2.8.0" + "memfs": "^2.8.0", + "prettier": "^1.16.4" } } From 6f1b480975a85657d365c05e9efaf57248e80972 Mon Sep 17 00:00:00 2001 From: marvinchin Date: Thu, 7 Mar 2019 16:13:13 +0800 Subject: [PATCH 2/3] Apply prettier formatting --- __mocks__/fs-extra-promise.js | 129 ++-- __mocks__/walk-sync.js | 65 +- asset/js/setup.js | 57 +- index.js | 150 +++-- src/Page.js | 587 +++++++++++------ src/Site.js | 607 ++++++++++++------ src/__mocks__/Page.js | 1 - .../src/handlers/cyclicReferenceError.js | 5 +- src/lib/markbind/src/parser.js | 382 +++++++---- src/lib/markbind/src/utils.js | 2 +- src/plugins/algolia.js | 16 +- src/plugins/filterTags.js | 34 +- src/util/cliUtil.js | 17 +- src/util/delay.js | 34 +- src/util/fsUtil.js | 15 +- src/util/logger.js | 21 +- test/functional/testUtil/diffPrinter.js | 24 +- .../layouts/testAfterSetup/scripts.js | 11 +- .../_markbind/plugins/testMarkbindPlugin.js | 15 +- .../_markbind/plugins/testMarkbindPlugin.js | 15 +- .../test_site/expected/markbind/js/setup.js | 57 +- .../layouts/testAfterSetup/scripts.js | 11 +- .../functional/test_site/testUtil/diffHtml.js | 17 +- test/unit/Site.test.js | 287 ++++++--- test/unit/cliUtil.test.js | 23 +- test/unit/parser.test.js | 102 +-- test/unit/utils/data.js | 183 +++--- 27 files changed, 1810 insertions(+), 1057 deletions(-) diff --git a/__mocks__/fs-extra-promise.js b/__mocks__/fs-extra-promise.js index f17b381295..fb0b85df9f 100644 --- a/__mocks__/fs-extra-promise.js +++ b/__mocks__/fs-extra-promise.js @@ -13,7 +13,7 @@ const { fs, vol } = require('memfs'); */ function rimraf(dirPath) { if (fs.existsSync(dirPath)) { - fs.readdirSync(dirPath).forEach((entry) => { + fs.readdirSync(dirPath).forEach(entry => { const entryPath = path.join(dirPath, entry); if (fs.lstatSync(entryPath).isDirectory()) { rimraf(entryPath); @@ -31,9 +31,8 @@ function rimraf(dirPath) { */ function createDir(pathArg) { const { dir, ext } = path.parse(pathArg); - const dirNames = (ext === '') - ? pathArg.split(path.sep) - : dir.split(pathArg.sep); + const dirNames = + ext === '' ? pathArg.split(path.sep) : dir.split(pathArg.sep); dirNames.reduce((accumDir, currentdir) => { const jointDir = path.join(accumDir, currentdir); @@ -60,7 +59,7 @@ function copyFileSync(src, dest) { function copyDirSync(src, dest) { if (fs.lstatSync(src).isDirectory()) { const files = fs.readdirSync(src); - files.forEach((file) => { + files.forEach(file => { const curSource = path.join(src, file); const curDest = path.join(dest, file); if (fs.lstatSync(curSource).isDirectory()) { @@ -90,7 +89,7 @@ fs.outputFileSync = (file, data) => { /** * Mocking fs-extra#emptydirSync */ -fs.emptydirSync = (dir) => { +fs.emptydirSync = dir => { if (!fs.existsSync(dir)) { createDir(dir); } else { @@ -114,7 +113,6 @@ fs.copySync = (src, dest) => { */ fs.readJsonSync = filePath => JSON.parse(fs.readFileSync(filePath, 'utf8')); - /** * Mocking fs-extra#outputJsonSync */ @@ -125,62 +123,67 @@ fs.outputJsonSync = (file, jsonData) => { /** * Mocking fs-extra-promise#removeAsync */ -fs.removeAsync = pathArg => new Promise((resolve, reject) => { - try { - if (fs.lstatSync(pathArg).isDirectory()) { - rimraf(pathArg); - } else { - fs.unlinkSync(pathArg); +fs.removeAsync = pathArg => + new Promise((resolve, reject) => { + try { + if (fs.lstatSync(pathArg).isDirectory()) { + rimraf(pathArg); + } else { + fs.unlinkSync(pathArg); + } + resolve(); + } catch (err) { + reject(err); } - resolve(); - } catch (err) { - reject(err); - } -}); + }); /** * Mocking fs-extra-promise#copyAsync */ -fs.copyAsync = (src, dest) => new Promise((resolve, reject) => { - try { - fs.copySync(src, dest); - resolve(); - } catch (err) { - reject(err); - } -}); +fs.copyAsync = (src, dest) => + new Promise((resolve, reject) => { + try { + fs.copySync(src, dest); + resolve(); + } catch (err) { + reject(err); + } + }); /** * Mocking fs-extra-promise#accessAsync */ -fs.accessAsync = pathArg => new Promise((resolve, reject) => { - try { - fs.accessSync(pathArg); - resolve(); - } catch (err) { - reject(err); - } -}); +fs.accessAsync = pathArg => + new Promise((resolve, reject) => { + try { + fs.accessSync(pathArg); + resolve(); + } catch (err) { + reject(err); + } + }); /** * Mocking fs-extra-promise#outputFileAsync */ -fs.outputFileAsync = (file, data) => new Promise((resolve, reject) => { - try { - fs.outputFileSync(file, data); - resolve(); - } catch (err) { - reject(err); - } -}); +fs.outputFileAsync = (file, data) => + new Promise((resolve, reject) => { + try { + fs.outputFileSync(file, data); + resolve(); + } catch (err) { + reject(err); + } + }); /** * Mocking fs-extra-promise#mkdirp */ -fs.mkdirp = dir => new Promise((resolve) => { - createDir(dir); - resolve(); -}); +fs.mkdirp = dir => + new Promise(resolve => { + createDir(dir); + resolve(); + }); /** * Mocking fs-extra#copySync @@ -196,25 +199,27 @@ fs.copySync = (src, dest) => { /** * Mocking fs-extra-promise#outputJsonAsync */ -fs.outputJsonAsync = (file, jsonData) => new Promise((resolve, reject) => { - try { - fs.outputJsonSync(file, jsonData); - resolve(); - } catch (err) { - reject(err); - } -}); +fs.outputJsonAsync = (file, jsonData) => + new Promise((resolve, reject) => { + try { + fs.outputJsonSync(file, jsonData); + resolve(); + } catch (err) { + reject(err); + } + }); /** - * Mocking fs-extra-promise#readJsonAsync + * Mocking fs-extra-promise#readJsonAsync */ -fs.readJsonAsync = filePath => new Promise((resolve, reject) => { - try { - resolve(fs.readJsonSync(filePath)); - } catch (err) { - reject(err); - } -}); +fs.readJsonAsync = filePath => + new Promise((resolve, reject) => { + try { + resolve(fs.readJsonSync(filePath)); + } catch (err) { + reject(err); + } + }); fs.vol = vol; module.exports = fs; diff --git a/__mocks__/walk-sync.js b/__mocks__/walk-sync.js index 71ebcadc62..69067efb28 100644 --- a/__mocks__/walk-sync.js +++ b/__mocks__/walk-sync.js @@ -35,11 +35,13 @@ function walkSync(baseDir, _options) { var mapFunct; if (options.includeBasePath) { - mapFunct = function (entry) { - return entry.basePath.split(path.sep).join('/') + '/' + entry.relativePath; + mapFunct = function(entry) { + return ( + entry.basePath.split(path.sep).join('/') + '/' + entry.relativePath + ); }; } else { - mapFunct = function (entry) { + mapFunct = function(entry) { return entry.relativePath; }; } @@ -75,24 +77,38 @@ function _walkSync(baseDir, options, _relativePath) { } var names = fs.readdirSync(baseDir + '/' + relativePath); - var entries = names.map(function (name) { - var entryRelativePath = relativePath + name; + var entries = names + .map(function(name) { + var entryRelativePath = relativePath + name; - if (ignoreMatcher && ignoreMatcher.match(entryRelativePath)) { - return; - } - - var fullPath = baseDir + '/' + entryRelativePath; - var stats = getStat(fullPath); + if (ignoreMatcher && ignoreMatcher.match(entryRelativePath)) { + return; + } - if (stats && stats.isDirectory()) { - return new Entry(entryRelativePath + '/', baseDir, stats.mode, stats.size, stats.mtime.getTime()); - } else { - return new Entry(entryRelativePath, baseDir, stats && stats.mode, stats && stats.size, stats && stats.mtime.getTime()); - } - }).filter(Boolean); + var fullPath = baseDir + '/' + entryRelativePath; + var stats = getStat(fullPath); + + if (stats && stats.isDirectory()) { + return new Entry( + entryRelativePath + '/', + baseDir, + stats.mode, + stats.size, + stats.mtime.getTime(), + ); + } else { + return new Entry( + entryRelativePath, + baseDir, + stats && stats.mode, + stats && stats.size, + stats && stats.mtime.getTime(), + ); + } + }) + .filter(Boolean); - var sortedEntries = entries.sort(function (a, b) { + var sortedEntries = entries.sort(function(a, b) { var aPath = a.relativePath; var bPath = b.relativePath; @@ -105,11 +121,14 @@ function _walkSync(baseDir, options, _relativePath) { } }); - for (var i=0; i { - jQuery(modal).detach().appendTo(jQuery('#app')); + jQuery(modal) + .detach() + .appendTo(jQuery('#app')); }); } function setupAnchors() { jQuery('h1, h2, h3, h4, h5, h6, .header-wrapper').each((index, heading) => { - jQuery(heading).on('mouseenter', - () => jQuery(heading).find('.fa.fa-anchor').css('visibility', 'visible')); - jQuery(heading).on('mouseleave', - () => jQuery(heading).find('.fa.fa-anchor').css('visibility', 'hidden')); + jQuery(heading).on('mouseenter', () => + jQuery(heading) + .find('.fa.fa-anchor') + .css('visibility', 'visible'), + ); + jQuery(heading).on('mouseleave', () => + jQuery(heading) + .find('.fa.fa-anchor') + .css('visibility', 'hidden'), + ); }); jQuery('.fa-anchor').each((index, anchor) => { - jQuery(anchor).on('click', function () { + jQuery(anchor).on('click', function() { window.location.href = jQuery(this).attr('href'); }); }); } function updateSearchData(vm) { - jQuery.getJSON(`${baseUrl}/siteData.json`) - .then((siteData) => { - // eslint-disable-next-line no-param-reassign - vm.searchData = siteData.pages; - }); + jQuery.getJSON(`${baseUrl}/siteData.json`).then(siteData => { + // eslint-disable-next-line no-param-reassign + vm.searchData = siteData.pages; + }); } const MarkBind = { executeAfterSetupScripts: jQuery.Deferred(), }; -MarkBind.afterSetup = (func) => { +MarkBind.afterSetup = func => { if (document.readyState !== 'loading') { func(); } else { @@ -71,7 +80,7 @@ function setupSiteNav() { // Add event listener for site-nav-btn to toggle itself and site navigation elements. const siteNavBtn = document.getElementById('site-nav-btn'); if (siteNavBtn) { - siteNavBtn.addEventListener('click', function () { + siteNavBtn.addEventListener('click', function() { this.classList.toggle('shift'); document.getElementById('site-nav').classList.toggle('open'); document.getElementById('site-nav-btn-wrap').classList.toggle('open'); @@ -80,19 +89,23 @@ function setupSiteNav() { // Creates event listener for all dropdown-btns in page. Array.prototype.forEach.call( document.getElementsByClassName('dropdown-btn'), - dropdownBtn => dropdownBtn.addEventListener('click', function () { - this.classList.toggle('dropdown-btn-open'); - const dropdownContent = this.nextElementSibling; - const dropdownIcon = this.lastElementChild; - dropdownContent.classList.toggle('dropdown-container-open'); - dropdownIcon.classList.toggle('rotate-icon'); - }), + dropdownBtn => + dropdownBtn.addEventListener('click', function() { + this.classList.toggle('dropdown-btn-open'); + const dropdownContent = this.nextElementSibling; + const dropdownIcon = this.lastElementChild; + dropdownContent.classList.toggle('dropdown-container-open'); + dropdownIcon.classList.toggle('rotate-icon'); + }), ); } function setupPageNav() { jQuery(window).on('activate.bs.scrollspy', (event, obj) => { - document.querySelectorAll(`a[href='${obj.relatedTarget}']`).item(0).scrollIntoView(false); + document + .querySelectorAll(`a[href='${obj.relatedTarget}']`) + .item(0) + .scrollIntoView(false); }); } diff --git a/index.js b/index.js index ff4d28d878..c8dbe245c2 100755 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ #!/usr/bin/env node - // Entry file for Markbind project const chokidar = require('chokidar'); const liveServer = require('live-server'); @@ -36,18 +35,15 @@ function handleError(error) { process.exitCode = 1; } -program - .allowUnknownOption() - .usage(' '); +program.allowUnknownOption().usage(' '); -program - .version(CLI_VERSION); +program.version(CLI_VERSION); program .command('init [root]') .alias('i') .description('init a markbind website project') - .action((root) => { + .action(root => { const rootFolder = path.resolve(root || process.cwd()); printHeader(); Site.initSite(rootFolder) @@ -61,11 +57,20 @@ program .command('serve [root]') .alias('s') .description('build then serve a website from a directory') - .option('-f, --force-reload', 'force a full reload of all site files when a file is changed') + .option( + '-f, --force-reload', + 'force a full reload of all site files when a file is changed', + ) .option('-n, --no-open', 'do not automatically open the site in browser') - .option('-o, --one-page ', 'render and serve only a single page in the site') + .option( + '-o, --one-page ', + 'render and serve only a single page in the site', + ) .option('-p, --port ', 'port for server to listen on (Default is 8080)') - .option('-s, --site-config ', 'specify the site config file (default: site.json)') + .option( + '-s, --site-config ', + 'specify the site config file (default: site.json)', + ) .action((userSpecifiedRoot, options) => { let rootFolder; try { @@ -82,47 +87,69 @@ program options.onePage = ensurePosix(options.onePage); } - const site = new Site(rootFolder, outputFolder, options.onePage, options.forceReload, options.siteConfig); - - const addHandler = (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file add: ${filePath}`); - Promise.resolve('').then(() => { - if (fsUtil.isSourceFile(filePath)) { - return site.rebuildSourceFiles(filePath); - } - return site.buildAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); + const site = new Site( + rootFolder, + outputFolder, + options.onePage, + options.forceReload, + options.siteConfig, + ); + + const addHandler = filePath => { + logger.info( + `[${new Date().toLocaleTimeString()}] Reload for file add: ${filePath}`, + ); + Promise.resolve('') + .then(() => { + if (fsUtil.isSourceFile(filePath)) { + return site.rebuildSourceFiles(filePath); + } + return site.buildAsset(filePath); + }) + .catch(err => { + logger.error(err.message); + }); }; - const changeHandler = (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file change: ${filePath}`); - Promise.resolve('').then(() => { - if (fsUtil.isSourceFile(filePath)) { - return site.rebuildAffectedSourceFiles(filePath); - } - return site.buildAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); + const changeHandler = filePath => { + logger.info( + `[${new Date().toLocaleTimeString()}] Reload for file change: ${filePath}`, + ); + Promise.resolve('') + .then(() => { + if (fsUtil.isSourceFile(filePath)) { + return site.rebuildAffectedSourceFiles(filePath); + } + return site.buildAsset(filePath); + }) + .catch(err => { + logger.error(err.message); + }); }; - const removeHandler = (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file deletion: ${filePath}`); - Promise.resolve('').then(() => { - if (fsUtil.isSourceFile(filePath)) { - return site.rebuildSourceFiles(filePath); - } - return site.removeAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); + const removeHandler = filePath => { + logger.info( + `[${new Date().toLocaleTimeString()}] Reload for file deletion: ${filePath}`, + ); + Promise.resolve('') + .then(() => { + if (fsUtil.isSourceFile(filePath)) { + return site.rebuildSourceFiles(filePath); + } + return site.removeAsset(filePath); + }) + .catch(err => { + logger.error(err.message); + }); }; // server config const serverConfig = { - open: options.open && (options.onePage ? `/${options.onePage.replace(/\.(md|mbd)$/, '.html')}` : true), + open: + options.open && + (options.onePage + ? `/${options.onePage.replace(/\.(md|mbd)$/, '.html')}` + : true), logLevel: 0, root: outputFolder, port: options.port || 8080, @@ -133,7 +160,7 @@ program site .readSiteConfig() - .then((config) => { + .then(config => { serverConfig.mount.push([config.baseUrl || '/', outputFolder]); return site.generate(); }) @@ -143,7 +170,8 @@ program logsFolder, outputFolder, /(^|[/\\])\../, - x => x.endsWith('___jb_tmp___'), x => x.endsWith('___jb_old___'), // IDE temp files + x => x.endsWith('___jb_tmp___'), + x => x.endsWith('___jb_old___'), // IDE temp files ], ignoreInitial: true, }); @@ -156,7 +184,8 @@ program const server = liveServer.start(serverConfig); server.addListener('listening', () => { const address = server.address(); - const serveHost = address.address === '0.0.0.0' ? '127.0.0.1' : address.address; + const serveHost = + address.address === '0.0.0.0' ? '127.0.0.1' : address.address; const serveURL = `http://${serveHost}:${address.port}`; logger.info(`Serving "${outputFolder}" at ${serveURL}`); logger.info('Press CTRL+C to stop ...'); @@ -168,12 +197,13 @@ program program .command('deploy') .alias('d') - .description('deploy the site to the repo\'s Github pages.') + .description("deploy the site to the repo's Github pages.") .option('-t, --travis [tokenVar]', 'deploy the site in Travis [GITHUB_TOKEN]') - .action((options) => { + .action(options => { const rootFolder = path.resolve(process.cwd()); const outputRoot = path.join(rootFolder, '_site'); - new Site(rootFolder, outputRoot).deploy(options.travis) + new Site(rootFolder, outputRoot) + .deploy(options.travis) .then(() => { logger.info('Deployed!'); }) @@ -184,8 +214,10 @@ program program .command('build [root] [output]') .alias('b') - .option('--baseUrl [baseUrl]', - 'optional flag which overrides baseUrl in site.json, leave argument empty for empty baseUrl') + .option( + '--baseUrl [baseUrl]', + 'optional flag which overrides baseUrl in site.json, leave argument empty for empty baseUrl', + ) .description('build a website') .action((userSpecifiedRoot, output, options) => { // if --baseUrl contains no arguments (options.baseUrl === true) then set baseUrl to empty string @@ -197,7 +229,9 @@ program handleError(err); } const defaultOutputRoot = path.join(rootFolder, '_site'); - const outputFolder = output ? path.resolve(process.cwd(), output) : defaultOutputRoot; + const outputFolder = output + ? path.resolve(process.cwd(), output) + : defaultOutputRoot; printHeader(); new Site(rootFolder, outputFolder) .generate(baseUrl) @@ -209,10 +243,16 @@ program program.parse(process.argv); -if (!program.args.length - || !(ACCEPTED_COMMANDS.concat(ACCEPTED_COMMANDS_ALIAS)).includes(process.argv[2])) { +if ( + !program.args.length || + !ACCEPTED_COMMANDS.concat(ACCEPTED_COMMANDS_ALIAS).includes(process.argv[2]) +) { if (program.args.length) { - logger.warn(`Command '${program.args[0]}' doesn't exist, run "markbind --help" to list commands.`); + logger.warn( + `Command '${ + program.args[0] + }' doesn't exist, run "markbind --help" to list commands.`, + ); } else { printHeader(); program.help(); diff --git a/src/Page.js b/src/Page.js index 61e6a1222e..7f24c30f72 100644 --- a/src/Page.js +++ b/src/Page.js @@ -37,17 +37,19 @@ const SITE_NAV_ID = 'site-nav'; const TITLE_PREFIX_SEPARATOR = ' - '; const ANCHOR_HTML = ''; -const DROPDOWN_BUTTON_ICON_HTML = '\n' - + '\n' - + ''; +const DROPDOWN_BUTTON_ICON_HTML = + '\n' + + '\n' + + ''; const DROPDOWN_EXPAND_KEYWORD = ':expanded:'; -const SITE_NAV_BUTTON_HTML = ''; +const SITE_NAV_BUTTON_HTML = + ''; const TEMP_NAVBAR_CLASS = 'temp-navbar'; const TEMP_DROPDOWN_CLASS = 'temp-dropdown'; @@ -99,9 +101,7 @@ function Page(pageConfig) { function addContentWrapper(pageData) { const $ = cheerio.load(pageData); $(`#${CONTENT_WRAPPER_ID}`).removeAttr('id'); - return `
\n\n` - + `${$.html()}\n` - + '
'; + return `
\n\n${$.html()}\n
`; } function calculateNewBaseUrl(filePath, root, lookUp) { @@ -145,7 +145,10 @@ function formatFooter(pageData) { function formatSiteNav(renderedSiteNav, src) { const $ = cheerio.load(renderedSiteNav); - const listItems = $.root().find('ul').first().children(); + const listItems = $.root() + .find('ul') + .first() + .children(); if (listItems.length === 0) { return renderedSiteNav; } @@ -157,45 +160,69 @@ function formatSiteNav(renderedSiteNav, src) { // Highlight current page const currentPageHtmlPath = src.replace(/\.(md|mbd)$/, '.html'); - listItems.find(`a[href='{{baseUrl}}/${currentPageHtmlPath}']`).addClass('current'); + listItems + .find(`a[href='{{baseUrl}}/${currentPageHtmlPath}']`) + .addClass('current'); - listItems.each(function () { + listItems.each(function() { // Tidy up the style of each list item $(this).attr('style', 'margin-top: 10px'); // Do not render dropdown menu for list items with tag if ($(this).children('a').length) { - const nestedList = $(this).children('ul').first(); + const nestedList = $(this) + .children('ul') + .first(); if (nestedList.length) { // Double wrap to counter replaceWith removing
  • nestedList.parent().wrap('
  • '); // Recursively format nested lists without dropdown wrapper - nestedList.parent().replaceWith(formatSiteNav(nestedList.parent().html(), src)); + nestedList + .parent() + .replaceWith(formatSiteNav(nestedList.parent().html(), src)); } - // Found nested list, render dropdown menu + // Found nested list, render dropdown menu } else if ($(this).children('ul').length) { - const nestedList = $(this).children('ul').first(); - const dropdownTitle = $(this).contents().not('ul'); + const nestedList = $(this) + .children('ul') + .first(); + const dropdownTitle = $(this) + .contents() + .not('ul'); // Replace the title with the dropdown wrapper dropdownTitle.remove(); // Check if dropdown is expanded by default or if the current page is in a dropdown - const shouldExpandDropdown = dropdownTitle.toString().includes(DROPDOWN_EXPAND_KEYWORD) - || Boolean(nestedList.find(`a[href='{{baseUrl}}/${currentPageHtmlPath}']`).text()); + const shouldExpandDropdown = + dropdownTitle.toString().includes(DROPDOWN_EXPAND_KEYWORD) || + Boolean( + nestedList + .find(`a[href='{{baseUrl}}/${currentPageHtmlPath}']`) + .text(), + ); if (shouldExpandDropdown) { const expandKeywordRegex = new RegExp(DROPDOWN_EXPAND_KEYWORD, 'g'); - const dropdownTitleWithoutKeyword = dropdownTitle.toString().replace(expandKeywordRegex, ''); - const rotatedIcon = cheerio.load(DROPDOWN_BUTTON_ICON_HTML, { xmlMode: false })('i') + const dropdownTitleWithoutKeyword = dropdownTitle + .toString() + .replace(expandKeywordRegex, ''); + const rotatedIcon = cheerio + .load(DROPDOWN_BUTTON_ICON_HTML, { xmlMode: false })('i') .addClass('rotate-icon'); - nestedList.wrap(''); - $(this).prepend(''); + nestedList.wrap( + '', + ); + $(this).prepend( + '', + ); } else { nestedList.wrap(''); - $(this).prepend(''); + $(this).prepend( + '', + ); } // Recursively format nested lists nestedList.replaceWith(formatSiteNav(nestedList.parent().html(), src)); @@ -220,7 +247,7 @@ function unique(array) { return array.filter((item, pos, self) => self.indexOf(item) === pos); } -Page.prototype.prepareTemplateData = function () { +Page.prototype.prepareTemplateData = function() { const prefixedTitle = this.titlePrefix ? this.titlePrefix + (this.title ? TITLE_PREFIX_SEPARATOR + this.title : '') : this.title; @@ -272,7 +299,7 @@ function getClosestHeading($, headingsSelector, element) { /** * Checks if page.frontMatter has a valid page navigation specifier */ -Page.prototype.isPageNavigationSpecifierValid = function () { +Page.prototype.isPageNavigationSpecifierValid = function() { const { pageNav } = this.frontMatter; return pageNav && (pageNav === 'default' || Number.isInteger(pageNav)); }; @@ -280,7 +307,7 @@ Page.prototype.isPageNavigationSpecifierValid = function () { /** * Generates element selector for page navigation, depending on specifier in front matter */ -Page.prototype.generateElementSelectorForPageNav = function (pageNav) { +Page.prototype.generateElementSelectorForPageNav = function(pageNav) { if (pageNav === 'default') { // Use specified navigation level or default in this.headingIndexingLevel return `${generateHeadingSelector(this.headingIndexingLevel)}, panel`; @@ -295,7 +322,7 @@ Page.prototype.generateElementSelectorForPageNav = function (pageNav) { * Collect headings outside of models and panels * @param content, html content of a page */ -Page.prototype.collectNavigableHeadings = function (content) { +Page.prototype.collectNavigableHeadings = function(content) { const { pageNav } = this.frontMatter; const elementSelector = this.generateElementSelectorForPageNav(pageNav); if (elementSelector === undefined) { @@ -306,13 +333,15 @@ Page.prototype.collectNavigableHeadings = function (content) { $(elementSelector).each((i, elem) => { // Check if heading or panel is already inside an unexpanded panel let isInsideUnexpandedPanel = false; - $(elem).parents('panel').each((j, elemParent) => { - if (elemParent.attribs.expanded === undefined) { - isInsideUnexpandedPanel = true; - return false; - } - return true; - }); + $(elem) + .parents('panel') + .each((j, elemParent) => { + if (elemParent.attribs.expanded === undefined) { + isInsideUnexpandedPanel = true; + return false; + } + return true; + }); if (isInsideUnexpandedPanel) { return; } @@ -334,33 +363,48 @@ Page.prototype.collectNavigableHeadings = function (content) { /** * Records headings and keywords inside rendered page into this.headings and this.keywords respectively */ -Page.prototype.collectHeadingsAndKeywords = function () { +Page.prototype.collectHeadingsAndKeywords = function() { const $ = cheerio.load(fs.readFileSync(this.resultPath)); // Re-initialise objects in the event of Site.regenerateAffectedPages this.headings = {}; this.keywords = {}; // Collect headings and keywords - this.collectHeadingsAndKeywordsInContent($(`#${CONTENT_WRAPPER_ID}`).html(), null, false, []); + this.collectHeadingsAndKeywordsInContent( + $(`#${CONTENT_WRAPPER_ID}`).html(), + null, + false, + [], + ); }; /** * Records headings and keywords inside content into this.headings and this.keywords respectively * @param content that contains the headings and keywords */ -Page.prototype.collectHeadingsAndKeywordsInContent = function (content, lastHeading, excludeHeadings, - sourceTraversalStack) { +Page.prototype.collectHeadingsAndKeywordsInContent = function( + content, + lastHeading, + excludeHeadings, + sourceTraversalStack, +) { let $ = cheerio.load(content); const headingsSelector = generateHeadingSelector(this.headingIndexingLevel); $('modal').remove(); - $('panel').not('panel panel') + $('panel') + .not('panel panel') .each((index, panel) => { if (panel.attribs.header) { - this.collectHeadingsAndKeywordsInContent(md.render(panel.attribs.header), - lastHeading, excludeHeadings, sourceTraversalStack); + this.collectHeadingsAndKeywordsInContent( + md.render(panel.attribs.header), + lastHeading, + excludeHeadings, + sourceTraversalStack, + ); } }) .each((index, panel) => { - const shouldExcludeHeadings = excludeHeadings || (panel.attribs.expanded === undefined); + const shouldExcludeHeadings = + excludeHeadings || panel.attribs.expanded === undefined; let closestHeading = getClosestHeading($, headingsSelector, panel); if (!closestHeading) { closestHeading = lastHeading; @@ -376,33 +420,56 @@ Page.prototype.collectHeadingsAndKeywordsInContent = function (content, lastHead const buildInnerDir = path.dirname(this.sourcePath); const resultInnerDir = path.dirname(this.resultPath); - const includeRelativeToBuildRootDirPath - = this.baseUrl ? path.relative(this.baseUrl, src) : src.substring(1); - const includeAbsoluteToBuildRootDirPath - = path.resolve(this.rootPath, includeRelativeToBuildRootDirPath); - const includeRelativeToInnerDirPath = path.relative(buildInnerDir, includeAbsoluteToBuildRootDirPath); - const includePath = path.resolve(resultInnerDir, includeRelativeToInnerDirPath); + const includeRelativeToBuildRootDirPath = this.baseUrl + ? path.relative(this.baseUrl, src) + : src.substring(1); + const includeAbsoluteToBuildRootDirPath = path.resolve( + this.rootPath, + includeRelativeToBuildRootDirPath, + ); + const includeRelativeToInnerDirPath = path.relative( + buildInnerDir, + includeAbsoluteToBuildRootDirPath, + ); + const includePath = path.resolve( + resultInnerDir, + includeRelativeToInnerDirPath, + ); const includeContent = fs.readFileSync(includePath); const childSourceTraversalStack = sourceTraversalStack.slice(); childSourceTraversalStack.push(includePath); - if (childSourceTraversalStack.length > CyclicReferenceError.MAX_RECURSIVE_DEPTH) { + if ( + childSourceTraversalStack.length > + CyclicReferenceError.MAX_RECURSIVE_DEPTH + ) { const error = new CyclicReferenceError(childSourceTraversalStack); throw error; } if (panel.attribs.fragment) { $ = cheerio.load(includeContent); - this.collectHeadingsAndKeywordsInContent($(`#${panel.attribs.fragment}`).html(), - closestHeading, shouldExcludeHeadings, - childSourceTraversalStack); + this.collectHeadingsAndKeywordsInContent( + $(`#${panel.attribs.fragment}`).html(), + closestHeading, + shouldExcludeHeadings, + childSourceTraversalStack, + ); } else { - this.collectHeadingsAndKeywordsInContent(includeContent, closestHeading, shouldExcludeHeadings, - childSourceTraversalStack); + this.collectHeadingsAndKeywordsInContent( + includeContent, + closestHeading, + shouldExcludeHeadings, + childSourceTraversalStack, + ); } } else { - this.collectHeadingsAndKeywordsInContent($(panel).html(), closestHeading, shouldExcludeHeadings, - sourceTraversalStack); + this.collectHeadingsAndKeywordsInContent( + $(panel).html(), + closestHeading, + shouldExcludeHeadings, + sourceTraversalStack, + ); } }); $ = cheerio.load(content); @@ -434,7 +501,7 @@ Page.prototype.collectHeadingsAndKeywordsInContent = function (content, lastHead * @param keyword to link * @param heading to link */ -Page.prototype.linkKeywordToHeading = function ($, keyword, heading) { +Page.prototype.linkKeywordToHeading = function($, keyword, heading) { const headingId = $(heading).attr('id'); if (!(headingId in this.keywords)) { this.keywords[headingId] = []; @@ -445,8 +512,8 @@ Page.prototype.linkKeywordToHeading = function ($, keyword, heading) { /** * Concatenates keywords in this.keywords to heading text in this.headings */ -Page.prototype.concatenateHeadingsAndKeywords = function () { - Object.keys(this.keywords).forEach((headingId) => { +Page.prototype.concatenateHeadingsAndKeywords = function() { + Object.keys(this.keywords).forEach(headingId => { const keywordString = this.keywords[headingId].join(', '); this.headings[headingId] += ` | ${keywordString}`; }); @@ -456,7 +523,7 @@ Page.prototype.concatenateHeadingsAndKeywords = function () { * Adds anchor links to headings in the page * @param content of the page */ -Page.prototype.addAnchors = function (content) { +Page.prototype.addAnchors = function(content) { const $ = cheerio.load(content, { xmlMode: false }); if (this.headingIndexingLevel > 0) { const headingsSelector = generateHeadingSelector(this.headingIndexingLevel); @@ -464,10 +531,15 @@ Page.prototype.addAnchors = function (content) { $(heading).append(ANCHOR_HTML.replace('#', `#${$(heading).attr('id')}`)); }); $('panel[header]').each((i, panel) => { - const panelHeading = cheerio.load(md.render(panel.attribs.header), { xmlMode: false }); + const panelHeading = cheerio.load(md.render(panel.attribs.header), { + xmlMode: false, + }); if (panelHeading(headingsSelector).length >= 1) { const headingId = $(panelHeading(headingsSelector)[0]).attr('id'); - const anchorIcon = ANCHOR_HTML.replace(/"/g, "'").replace('#', `#${headingId}`); + const anchorIcon = ANCHOR_HTML.replace(/"/g, "'").replace( + '#', + `#${headingId}`, + ); $(panel).attr('header', `${$(panel).attr('header')}${anchorIcon}`); } }); @@ -479,8 +551,8 @@ Page.prototype.addAnchors = function (content) { * Records the dynamic or static included files into this.includedFiles * @param dependencies array of maps of the external dependency and where it is included */ -Page.prototype.collectIncludedFiles = function (dependencies) { - dependencies.forEach((dependency) => { +Page.prototype.collectIncludedFiles = function(dependencies) { + dependencies.forEach(dependency => { this.includedFiles[dependency.to] = true; }); }; @@ -489,7 +561,7 @@ Page.prototype.collectIncludedFiles = function (dependencies) { * Records the front matter into this.frontMatter * @param includedPage a page with its dependencies included */ -Page.prototype.collectFrontMatter = function (includedPage) { +Page.prototype.collectFrontMatter = function(includedPage) { const $ = cheerio.load(includedPage); const frontMatter = $('frontmatter'); if (frontMatter.text().trim()) { @@ -505,9 +577,10 @@ Page.prototype.collectFrontMatter = function (includedPage) { this.frontMatter = parsedData.attributes; this.frontMatter.src = this.src; // Title specified in site.json will override title specified in front matter - this.frontMatter.title = (this.title || this.frontMatter.title || ''); + this.frontMatter.title = this.title || this.frontMatter.title || ''; // Layout specified in site.json will override layout specified in the front matter - this.frontMatter.layout = (this.layout || this.frontMatter.layout || LAYOUT_DEFAULT_NAME); + this.frontMatter.layout = + this.layout || this.frontMatter.layout || LAYOUT_DEFAULT_NAME; } else { // Page is addressable but no front matter specified this.frontMatter = { @@ -523,7 +596,7 @@ Page.prototype.collectFrontMatter = function (includedPage) { * Removes the front matter from an included page * @param includedPage a page with its dependencies included */ -Page.prototype.removeFrontMatter = function (includedPage) { +Page.prototype.removeFrontMatter = function(includedPage) { const $ = cheerio.load(includedPage); const frontMatter = $('frontmatter'); frontMatter.remove(); @@ -534,13 +607,17 @@ Page.prototype.removeFrontMatter = function (includedPage) { * Inserts the footer specified in front matter to the end of the page * @param pageData a page with its front matter collected */ -Page.prototype.insertFooter = function (pageData) { +Page.prototype.insertFooter = function(pageData) { const { footer } = this.frontMatter; let footerFile; if (footer) { footerFile = path.join(FOOTERS_FOLDER_PATH, footer); } else { - footerFile = path.join(LAYOUT_FOLDER_PATH, this.frontMatter.layout, LAYOUT_FOOTER); + footerFile = path.join( + LAYOUT_FOLDER_PATH, + this.frontMatter.layout, + LAYOUT_FOOTER, + ); } const footerPath = path.join(this.rootPath, footerFile); if (!fs.existsSync(footerPath)) { @@ -551,9 +628,15 @@ Page.prototype.insertFooter = function (pageData) { // Set footer file as an includedFile this.includedFiles[footerPath] = true; // Map variables - const newBaseUrl = calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || ''; - const userDefinedVariables = this.userDefinedVariablesMap[path.join(this.rootPath, newBaseUrl)]; - return `${pageData}\n${nunjucks.renderString(footerContent, userDefinedVariables)}`; + const newBaseUrl = + calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || ''; + const userDefinedVariables = this.userDefinedVariablesMap[ + path.join(this.rootPath, newBaseUrl) + ]; + return `${pageData}\n${nunjucks.renderString( + footerContent, + userDefinedVariables, + )}`; }; /** @@ -561,13 +644,17 @@ Page.prototype.insertFooter = function (pageData) { * @param pageData, a page with its front matter collected * @throws (Error) if there is more than one instance of the tag */ -Page.prototype.insertSiteNav = function (pageData) { +Page.prototype.insertSiteNav = function(pageData) { const { siteNav } = this.frontMatter; let siteNavFile; if (siteNav) { siteNavFile = path.join(NAVIGATION_FOLDER_PATH, siteNav); } else { - siteNavFile = path.join(LAYOUT_FOLDER_PATH, this.frontMatter.layout, LAYOUT_NAVIGATION); + siteNavFile = path.join( + LAYOUT_FOLDER_PATH, + this.frontMatter.layout, + LAYOUT_NAVIGATION, + ); } // Retrieve Markdown file contents const siteNavPath = path.join(this.rootPath, siteNavFile); @@ -581,15 +668,26 @@ Page.prototype.insertSiteNav = function (pageData) { // Set siteNav file as an includedFile this.includedFiles[siteNavPath] = true; // Map variables - const newBaseUrl = calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || ''; - const userDefinedVariables = this.userDefinedVariablesMap[path.join(this.rootPath, newBaseUrl)]; - const siteNavMappedData = nunjucks.renderString(siteNavContent, userDefinedVariables); + const newBaseUrl = + calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || ''; + const userDefinedVariables = this.userDefinedVariablesMap[ + path.join(this.rootPath, newBaseUrl) + ]; + const siteNavMappedData = nunjucks.renderString( + siteNavContent, + userDefinedVariables, + ); // Convert to HTML const siteNavDataSelector = cheerio.load(siteNavMappedData); if (siteNavDataSelector('navigation').length > 1) { throw new Error(`More than one tag found in ${siteNavPath}`); } else if (siteNavDataSelector('navigation').length === 1) { - const siteNavHtml = md.render(siteNavDataSelector('navigation').html().trim().replace(/\n\s*\n/g, '\n')); + const siteNavHtml = md.render( + siteNavDataSelector('navigation') + .html() + .trim() + .replace(/\n\s*\n/g, '\n'), + ); const formattedSiteNav = formatSiteNav(siteNavHtml, this.src); siteNavDataSelector('navigation').replaceWith(formattedSiteNav); } @@ -597,21 +695,24 @@ Page.prototype.insertSiteNav = function (pageData) { const wrappedSiteNav = `
    \n${siteNavDataSelector.html()}\n
    `; const wrappedPageData = `
    \n${pageData}\n
    `; - return `
    ` - + `${wrappedSiteNav}` - + `${SITE_NAV_BUTTON_HTML}` - + `${wrappedPageData}` - + '
    '; + return ( + `
    ` + + `${wrappedSiteNav}` + + `${SITE_NAV_BUTTON_HTML}` + + `${wrappedPageData}` + + '
    ' + ); }; /** * Inserts wrapper for page nav contents CSS manipulation */ -Page.prototype.insertPageNavWrapper = function (pageData) { +Page.prototype.insertPageNavWrapper = function(pageData) { if (this.isPageNavigationSpecifierValid()) { - const wrappedPageData = `
    \n` - + `${pageData}\n` - + '
    \n'; + const wrappedPageData = + `
    \n` + + `${pageData}\n` + + '
    \n'; return wrappedPageData; } return pageData; @@ -622,17 +723,22 @@ Page.prototype.insertPageNavWrapper = function (pageData) { * * A stack is used to maintain proper indentation levels for the headings at different heading levels. */ -Page.prototype.generatePageNavHeadingHtml = function () { +Page.prototype.generatePageNavHeadingHtml = function() { let headingHTML = ''; const headingStack = []; - Object.keys(this.navigableHeadings).forEach((key) => { + Object.keys(this.navigableHeadings).forEach(key => { const currentHeadingLevel = this.navigableHeadings[key].level; - const currentHeadingHTML = `
    ` - + `${this.navigableHeadings[key].text}‎\n`; - const nestedHeadingHTML = '\n'; headingStack.pop(); } @@ -674,46 +789,54 @@ Page.prototype.generatePageNavHeadingHtml = function () { * Generates page navigation's header if specified in this.frontMatter * @returns string string */ -Page.prototype.generatePageNavTitleHtml = function () { +Page.prototype.generatePageNavTitleHtml = function() { const { pageNavTitle } = this.frontMatter; return pageNavTitle - ? '' - + `${pageNavTitle.toString()}` - + '' + ? '' + + `${pageNavTitle.toString()}` + + '' : ''; }; /** * Insert page navigation bar with headings up to headingIndexingLevel */ -Page.prototype.insertPageNav = function () { +Page.prototype.insertPageNav = function() { if (this.isPageNavigationSpecifierValid()) { const $ = cheerio.load(this.content); this.navigableHeadings = {}; this.collectNavigableHeadings($(`#${CONTENT_WRAPPER_ID}`).html()); const pageNavHeadingHTML = this.generatePageNavHeadingHtml(); const pageNavTitleHtml = this.generatePageNavTitleHtml(); - const pageNavHtml = '\n'; - this.content = htmlBeautify(`${pageNavHtml}\n${this.content}`, { indent_size: 2 }); + const pageNavHtml = + '\n'; + this.content = htmlBeautify(`${pageNavHtml}\n${this.content}`, { + indent_size: 2, + }); } }; -Page.prototype.collectHeadFiles = function (baseUrl, hostBaseUrl) { +Page.prototype.collectHeadFiles = function(baseUrl, hostBaseUrl) { const { head } = this.frontMatter; let headFiles; const collectedTopContent = []; const collectedBottomContent = []; if (head) { - headFiles = head.replace(/, */g, ',').split(',').map(headFile => path.join(HEAD_FOLDER_PATH, headFile)); + headFiles = head + .replace(/, */g, ',') + .split(',') + .map(headFile => path.join(HEAD_FOLDER_PATH, headFile)); } else { - headFiles = [path.join(LAYOUT_FOLDER_PATH, this.frontMatter.layout, LAYOUT_HEAD)]; + headFiles = [ + path.join(LAYOUT_FOLDER_PATH, this.frontMatter.layout, LAYOUT_HEAD), + ]; } - headFiles.forEach((headFile) => { + headFiles.forEach(headFile => { const headFilePath = path.join(this.rootPath, headFile); if (!fs.existsSync(headFilePath)) { return; @@ -722,43 +845,59 @@ Page.prototype.collectHeadFiles = function (baseUrl, hostBaseUrl) { // Set head file as an includedFile this.includedFiles[headFilePath] = true; // Map variables - const newBaseUrl = calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || ''; - const userDefinedVariables = this.userDefinedVariablesMap[path.join(this.rootPath, newBaseUrl)]; - const headFileMappedData = nunjucks.renderString(headFileContent, userDefinedVariables).trim(); + const newBaseUrl = + calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || + ''; + const userDefinedVariables = this.userDefinedVariablesMap[ + path.join(this.rootPath, newBaseUrl) + ]; + const headFileMappedData = nunjucks + .renderString(headFileContent, userDefinedVariables) + .trim(); // Split top and bottom contents const $ = cheerio.load(headFileMappedData, { xmlMode: false }); if ($('head-top').length) { - collectedTopContent.push(nunjucks.renderString($('head-top').html(), { baseUrl, hostBaseUrl }) - .trim() - .replace(/\n\s*\n/g, '\n') - .replace(/\n/g, '\n ')); + collectedTopContent.push( + nunjucks + .renderString($('head-top').html(), { baseUrl, hostBaseUrl }) + .trim() + .replace(/\n\s*\n/g, '\n') + .replace(/\n/g, '\n '), + ); $('head-top').remove(); } - collectedBottomContent.push(nunjucks.renderString($.html(), { baseUrl, hostBaseUrl }) - .trim() - .replace(/\n\s*\n/g, '\n') - .replace(/\n/g, '\n ')); + collectedBottomContent.push( + nunjucks + .renderString($.html(), { baseUrl, hostBaseUrl }) + .trim() + .replace(/\n\s*\n/g, '\n') + .replace(/\n/g, '\n '), + ); }); this.headFileTopContent = collectedTopContent.join('\n '); this.headFileBottomContent = collectedBottomContent.join('\n '); }; -Page.prototype.insertTemporaryStyles = function (pageData) { +Page.prototype.insertTemporaryStyles = function(pageData) { const $ = cheerio.load(pageData); // inject temporary navbar styles $('navbar').addClass(TEMP_NAVBAR_CLASS); // inject temporary dropdown styles $('dropdown').each((i, element) => { const attributes = element.attribs; - const placeholder = `${attributes.text}`; + const placeholder = `${ + attributes.text + }`; $(element).before(placeholder); - $(element).prev().addClass(TEMP_DROPDOWN_PLACEHOLDER_CLASS); + $(element) + .prev() + .addClass(TEMP_DROPDOWN_PLACEHOLDER_CLASS); $(element).addClass(TEMP_DROPDOWN_CLASS); }); return $.html(); }; -Page.prototype.generate = function (builtFiles) { +Page.prototype.generate = function(builtFiles) { this.includedFiles = {}; this.includedFiles[this.sourcePath] = true; @@ -771,15 +910,16 @@ Page.prototype.generate = function (builtFiles) { userDefinedVariablesMap: this.userDefinedVariablesMap, }; return new Promise((resolve, reject) => { - markbinder.includeFile(this.sourcePath, fileConfig) - .then((result) => { + markbinder + .includeFile(this.sourcePath, fileConfig) + .then(result => { this.collectFrontMatter(result); return this.removeFrontMatter(result); }) .then(result => addContentWrapper(result)) .then(result => this.preRender(result)) .then(result => this.insertPageNavWrapper(result)) - .then(result => this.insertSiteNav((result))) + .then(result => this.insertSiteNav(result)) .then(result => this.insertTemporaryStyles(result)) .then(result => this.insertFooter(result)) // Footer has to be inserted last to ensure proper formatting .then(result => formatFooter(result)) @@ -789,22 +929,34 @@ Page.prototype.generate = function (builtFiles) { .then(result => this.addAnchors(result)) .then(result => this.postRender(result)) .then(result => this.collectPluginsAssets(result)) - .then((result) => { + .then(result => { this.content = htmlBeautify(result, { indent_size: 2 }); - const newBaseUrl = calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap); - const baseUrl = newBaseUrl ? `${this.baseUrl}/${newBaseUrl}` : this.baseUrl; + const newBaseUrl = calculateNewBaseUrl( + this.sourcePath, + this.rootPath, + this.baseUrlMap, + ); + const baseUrl = newBaseUrl + ? `${this.baseUrl}/${newBaseUrl}` + : this.baseUrl; const hostBaseUrl = this.baseUrl; this.addLayoutFiles(); this.collectHeadFiles(baseUrl, hostBaseUrl); - this.content = nunjucks.renderString(this.content, { baseUrl, hostBaseUrl }); + this.content = nunjucks.renderString(this.content, { + baseUrl, + hostBaseUrl, + }); this.insertPageNav(); - return fs.outputFileAsync(this.resultPath, this.template(this.prepareTemplateData())); + return fs.outputFileAsync( + this.resultPath, + this.template(this.prepareTemplateData()), + ); }) .then(() => { const resolvingFiles = []; - unique(markbinder.getDynamicIncludeSrc()).forEach((source) => { + unique(markbinder.getDynamicIncludeSrc()).forEach(source => { if (!FsUtil.isUrl(source.to)) { resolvingFiles.push(this.resolveDependency(source, builtFiles)); } @@ -825,12 +977,15 @@ Page.prototype.generate = function (builtFiles) { /** * Entry point for plugin pre-render */ -Page.prototype.preRender = function (content) { +Page.prototype.preRender = function(content) { let preRenderedContent = content; Object.entries(this.plugins).forEach(([pluginName, plugin]) => { if (plugin.preRender) { - preRenderedContent - = plugin.preRender(preRenderedContent, this.pluginsContext[pluginName] || {}, this.frontMatter); + preRenderedContent = plugin.preRender( + preRenderedContent, + this.pluginsContext[pluginName] || {}, + this.frontMatter, + ); } }); return preRenderedContent; @@ -839,12 +994,15 @@ Page.prototype.preRender = function (content) { /** * Entry point for plugin post-render */ -Page.prototype.postRender = function (content) { +Page.prototype.postRender = function(content) { let postRenderedContent = content; Object.entries(this.plugins).forEach(([pluginName, plugin]) => { if (plugin.postRender) { - postRenderedContent - = plugin.postRender(postRenderedContent, this.pluginsContext[pluginName] || {}, this.frontMatter); + postRenderedContent = plugin.postRender( + postRenderedContent, + this.pluginsContext[pluginName] || {}, + this.frontMatter, + ); } }); return postRenderedContent; @@ -853,7 +1011,7 @@ Page.prototype.postRender = function (content) { /** * Collect page content inserted by plugins */ -Page.prototype.collectPluginsAssets = function (content) { +Page.prototype.collectPluginsAssets = function(content) { let links = []; let scripts = []; @@ -866,13 +1024,21 @@ Page.prototype.collectPluginsAssets = function (content) { Object.entries(this.plugins).forEach(([pluginName, plugin]) => { if (plugin.getLinks) { - const pluginLinks - = plugin.getLinks(content, this.pluginsContext[pluginName], this.frontMatter, linkUtils); + const pluginLinks = plugin.getLinks( + content, + this.pluginsContext[pluginName], + this.frontMatter, + linkUtils, + ); links = links.concat(pluginLinks); } if (plugin.getScripts) { - const pluginScripts - = plugin.getScripts(content, this.pluginsContext[pluginName], this.frontMatter, scriptUtils); + const pluginScripts = plugin.getScripts( + content, + this.pluginsContext[pluginName], + this.frontMatter, + scriptUtils, + ); scripts = scripts.concat(pluginScripts); } }); @@ -885,9 +1051,17 @@ Page.prototype.collectPluginsAssets = function (content) { /** * Adds linked layout files to page assets */ -Page.prototype.addLayoutFiles = function () { - this.asset.layoutScript = path.join(this.layoutsAssetPath, this.frontMatter.layout, 'scripts.js'); - this.asset.layoutStyle = path.join(this.layoutsAssetPath, this.frontMatter.layout, 'styles.css'); +Page.prototype.addLayoutFiles = function() { + this.asset.layoutScript = path.join( + this.layoutsAssetPath, + this.frontMatter.layout, + 'scripts.js', + ); + this.asset.layoutStyle = path.join( + this.layoutsAssetPath, + this.frontMatter.layout, + 'styles.css', + ); }; /** @@ -896,12 +1070,17 @@ Page.prototype.addLayoutFiles = function () { * @param dependency a map of the external dependency and where it is included * @param builtFiles set of files already pre-rendered by another page */ -Page.prototype.resolveDependency = function (dependency, builtFiles) { +Page.prototype.resolveDependency = function(dependency, builtFiles) { const source = dependency.from; const file = dependency.asIfTo; return new Promise((resolve, reject) => { - const resultDir = path.dirname(path.resolve(this.resultPath, path.relative(this.sourcePath, file))); - const resultPath = path.join(resultDir, FsUtil.setExtension(path.basename(file), '._include_.html')); + const resultDir = path.dirname( + path.resolve(this.resultPath, path.relative(this.sourcePath, file)), + ); + const resultPath = path.join( + resultDir, + FsUtil.setExtension(path.basename(file), '._include_.html'), + ); if (builtFiles[resultPath]) { return resolve(); @@ -920,43 +1099,67 @@ Page.prototype.resolveDependency = function (dependency, builtFiles) { let tempPath; if (FsUtil.isInRoot(this.rootPath, file)) { - tempPath = path.join(path.dirname(this.tempPath), path.relative(this.rootPath, file)); + tempPath = path.join( + path.dirname(this.tempPath), + path.relative(this.rootPath, file), + ); } else { - logger.info(`Converting dynamic external resource ${file} to ${resultPath}`); - tempPath = path.join(path.dirname(this.tempPath), '.external', path.basename(file)); + logger.info( + `Converting dynamic external resource ${file} to ${resultPath}`, + ); + tempPath = path.join( + path.dirname(this.tempPath), + '.external', + path.basename(file), + ); } - return markbinder.includeFile(dependency.to, { - baseUrlMap: this.baseUrlMap, - userDefinedVariablesMap: this.userDefinedVariablesMap, - rootPath: this.rootPath, - cwf: file, - }) - .then(result => this.removeFrontMatter(result)) - .then(result => markbinder.resolveBaseUrl(result, { + return markbinder + .includeFile(dependency.to, { baseUrlMap: this.baseUrlMap, + userDefinedVariablesMap: this.userDefinedVariablesMap, rootPath: this.rootPath, - isDynamic: true, - dynamicSource: source, - })) + cwf: file, + }) + .then(result => this.removeFrontMatter(result)) + .then(result => + markbinder.resolveBaseUrl(result, { + baseUrlMap: this.baseUrlMap, + rootPath: this.rootPath, + isDynamic: true, + dynamicSource: source, + }), + ) .then(result => fs.outputFileAsync(tempPath, result)) - .then(() => markbinder.renderFile(tempPath, { - baseUrlMap: this.baseUrlMap, - rootPath: this.rootPath, - })) - .then((result) => { + .then(() => + markbinder.renderFile(tempPath, { + baseUrlMap: this.baseUrlMap, + rootPath: this.rootPath, + }), + ) + .then(result => { // resolve the site base url here - const newBaseUrl = calculateNewBaseUrl(file, this.rootPath, this.baseUrlMap); - const baseUrl = newBaseUrl ? `${this.baseUrl}/${newBaseUrl}` : this.baseUrl; + const newBaseUrl = calculateNewBaseUrl( + file, + this.rootPath, + this.baseUrlMap, + ); + const baseUrl = newBaseUrl + ? `${this.baseUrl}/${newBaseUrl}` + : this.baseUrl; const hostBaseUrl = this.baseUrl; const content = nunjucks.renderString(result, { baseUrl, hostBaseUrl }); - return fs.outputFileAsync(resultPath, htmlBeautify(content, { indent_size: 2 })); + return fs.outputFileAsync( + resultPath, + htmlBeautify(content, { indent_size: 2 }), + ); }) .then(() => { // Recursion call to resolve nested dependency const resolvingFiles = []; - unique(markbinder.getDynamicIncludeSrc()).forEach((src) => { - if (!FsUtil.isUrl(src.to)) resolvingFiles.push(this.resolveDependency(src, builtFiles)); + unique(markbinder.getDynamicIncludeSrc()).forEach(src => { + if (!FsUtil.isUrl(src.to)) + resolvingFiles.push(this.resolveDependency(src, builtFiles)); }); return Promise.all(resolvingFiles); }) diff --git a/src/Site.js b/src/Site.js index 0290b28942..af361e7be3 100644 --- a/src/Site.js +++ b/src/Site.js @@ -82,53 +82,77 @@ const SITE_CONFIG_DEFAULT = { }, }; -const FOOTER_DEFAULT = '
    \n' - + '
    \n' - + ' This is a dynamic height footer that supports markdown :smile:!\n' - + '
    \n' - + ' \n' - + '
    \n' - + ' [Generated by {{MarkBind}} on {{timestamp}}]\n' - + '
    \n' - + '
    \n'; - -const INDEX_MARKDOWN_DEFAULT = '\n' - + ' title: "Hello World"\n' - + ' footer: footer.md\n' - + ' siteNav: site-nav.md\n' - + '\n\n' - + '# Hello world\n' - + 'Welcome to your page generated with MarkBind.\n'; - -const SITE_NAV_DEFAULT = '\n' - + '* [Home :glyphicon-home:]({{baseUrl}}/index.html)\n' - + '\n'; - -const LAYOUT_SCRIPTS_DEFAULT = 'MarkBind.afterSetup(() => {\n' - + ' // Include code to be called after MarkBind setup here.\n' - + '});\n'; - -const USER_VARIABLES_DEFAULT = '\n' - + 'To inject this HTML segment in your markbind files, use {{ example }} where you want to place it.\n' - + 'More generally, surround the segment\'s id with double curly braces.\n' - + ''; +const FOOTER_DEFAULT = + '
    \n' + + '
    \n' + + ' This is a dynamic height footer that supports markdown :smile:!\n' + + '
    \n' + + ' \n' + + '
    \n' + + ' [Generated by {{MarkBind}} on {{timestamp}}]\n' + + '
    \n' + + '
    \n'; + +const INDEX_MARKDOWN_DEFAULT = + '\n' + + ' title: "Hello World"\n' + + ' footer: footer.md\n' + + ' siteNav: site-nav.md\n' + + '\n\n' + + '# Hello world\n' + + 'Welcome to your page generated with MarkBind.\n'; + +const SITE_NAV_DEFAULT = + '\n' + + '* [Home :glyphicon-home:]({{baseUrl}}/index.html)\n' + + '\n'; + +const LAYOUT_SCRIPTS_DEFAULT = + 'MarkBind.afterSetup(() => {\n' + + ' // Include code to be called after MarkBind setup here.\n' + + '});\n'; + +const USER_VARIABLES_DEFAULT = + '\n' + + 'To inject this HTML segment in your markbind files, use {{ example }} where you want to place it.\n' + + "More generally, surround the segment's id with double curly braces.\n" + + ''; const GENERATE_SITE_LOGGING_KEY = 'Generate Site'; const MARKBIND_WEBSITE_URL = 'https://markbind.org/'; const MARKBIND_LINK_HTML = `MarkBind ${CLI_VERSION}`; -function Site(rootPath, outputPath, onePagePath, forceReload = false, siteConfigPath = SITE_CONFIG_NAME) { +function Site( + rootPath, + outputPath, + onePagePath, + forceReload = false, + siteConfigPath = SITE_CONFIG_NAME, +) { this.rootPath = rootPath; this.outputPath = outputPath; this.tempPath = path.join(rootPath, TEMP_FOLDER_NAME); // MarkBind assets to be copied - this.siteAssetsSrcPath = path.resolve(__dirname, '..', SITE_ASSET_FOLDER_NAME); - this.siteAssetsDestPath = path.join(outputPath, TEMPLATE_SITE_ASSET_FOLDER_NAME); + this.siteAssetsSrcPath = path.resolve( + __dirname, + '..', + SITE_ASSET_FOLDER_NAME, + ); + this.siteAssetsDestPath = path.join( + outputPath, + TEMPLATE_SITE_ASSET_FOLDER_NAME, + ); // Page template path - this.pageTemplatePath = path.join(__dirname, TEMPLATE_ROOT_FOLDER_NAME, PAGE_TEMPLATE_NAME); - this.pageTemplate = ejs.compile(fs.readFileSync(this.pageTemplatePath, 'utf8')); + this.pageTemplatePath = path.join( + __dirname, + TEMPLATE_ROOT_FOLDER_NAME, + PAGE_TEMPLATE_NAME, + ); + this.pageTemplate = ejs.compile( + fs.readFileSync(this.pageTemplatePath, 'utf8'), + ); this.pages = []; // Other properties @@ -152,7 +176,7 @@ function rejectHandler(reject, error, removeFolders) { .then(() => { reject(error); }) - .catch((err) => { + .catch(err => { reject(new Error(`${error.message}\n${err.message}`)); }); } @@ -160,15 +184,21 @@ function rejectHandler(reject, error, removeFolders) { function getIconsMap() { const fontAwesomePath = path.join(__dirname, FONT_AWESOME_PATH); const glyphiconsPath = path.join(__dirname, GLYPHICONS_PATH); - const fontAwesomeClasses = fs.readFileSync(fontAwesomePath, 'utf8').trimRight().split(/\r?\n/); - const glyphiconsClasses = fs.readFileSync(glyphiconsPath, 'utf8').trimRight().split(/\r?\n/); + const fontAwesomeClasses = fs + .readFileSync(fontAwesomePath, 'utf8') + .trimRight() + .split(/\r?\n/); + const glyphiconsClasses = fs + .readFileSync(glyphiconsPath, 'utf8') + .trimRight() + .split(/\r?\n/); const iconsMap = {}; - fontAwesomeClasses.forEach((fontAwesomeClass) => { + fontAwesomeClasses.forEach(fontAwesomeClass => { const name = fontAwesomeClass.replace(' fa', '').replace(/-/g, '_'); const html = ``; iconsMap[name] = html; }); - glyphiconsClasses.forEach((glyphiconClass) => { + glyphiconsClasses.forEach(glyphiconClass => { const name = glyphiconClass.replace(/-/g, '_'); const html = ``; iconsMap[name] = html; @@ -189,7 +219,7 @@ function setExtension(filename, ext) { * * @param rootPath */ -Site.initSite = function (rootPath) { +Site.initSite = function(rootPath) { const boilerplatePath = path.join(rootPath, BOILERPLATE_FOLDER_NAME); const configPath = path.join(rootPath, SITE_CONFIG_NAME); const footerPath = path.join(rootPath, FOOTER_PATH); @@ -198,7 +228,10 @@ Site.initSite = function (rootPath) { const siteNavPath = path.join(rootPath, SITE_NAV_PATH); const siteLayoutPath = path.join(rootPath, LAYOUT_FOLDER_PATH); const siteLayoutDefaultPath = path.join(siteLayoutPath, LAYOUT_DEFAULT_NAME); - const siteDefaultLayoutScriptsPath = path.join(siteLayoutDefaultPath, LAYOUT_SCRIPTS_PATH); + const siteDefaultLayoutScriptsPath = path.join( + siteLayoutDefaultPath, + LAYOUT_SCRIPTS_PATH, + ); const sitePluginPath = path.join(rootPath, PROJECT_PLUGIN_FOLDER_NAME); const userDefinedVariablesPath = path.join(rootPath, USER_VARIABLES_PATH); // TODO: log the generate info @@ -229,7 +262,10 @@ Site.initSite = function (rootPath) { if (fs.existsSync(userDefinedVariablesPath)) { return Promise.resolve(); } - return fs.outputFileAsync(userDefinedVariablesPath, USER_VARIABLES_DEFAULT); + return fs.outputFileAsync( + userDefinedVariablesPath, + USER_VARIABLES_DEFAULT, + ); }) .then(() => fs.accessAsync(footerPath)) .catch(() => { @@ -267,7 +303,7 @@ Site.initSite = function (rootPath) { return fs.mkdirp(siteLayoutDefaultPath); }) .then(() => { - LAYOUT_FILES.forEach((layoutFile) => { + LAYOUT_FILES.forEach(layoutFile => { const layoutFilePath = path.join(siteLayoutDefaultPath, layoutFile); fs.accessAsync(layoutFilePath).catch(() => { if (fs.existsSync(layoutFilePath)) { @@ -282,7 +318,10 @@ Site.initSite = function (rootPath) { if (fs.existsSync(siteDefaultLayoutScriptsPath)) { return Promise.resolve(); } - return fs.outputFileAsync(siteDefaultLayoutScriptsPath, LAYOUT_SCRIPTS_DEFAULT); + return fs.outputFileAsync( + siteDefaultLayoutScriptsPath, + LAYOUT_SCRIPTS_DEFAULT, + ); }) .then(() => fs.accessAsync(sitePluginPath)) .catch(() => { @@ -296,24 +335,32 @@ Site.initSite = function (rootPath) { }); }; -Site.prototype.readSiteConfig = function (baseUrl) { +Site.prototype.readSiteConfig = function(baseUrl) { return new Promise((resolve, reject) => { const siteConfigPath = path.join(this.rootPath, this.siteConfigPath); fs.readJsonAsync(siteConfigPath) - .then((config) => { + .then(config => { this.siteConfig = config; - this.siteConfig.baseUrl = (baseUrl === undefined) ? this.siteConfig.baseUrl : baseUrl; - this.siteConfig.enableSearch = (config.enableSearch === undefined) || config.enableSearch; + this.siteConfig.baseUrl = + baseUrl === undefined ? this.siteConfig.baseUrl : baseUrl; + this.siteConfig.enableSearch = + config.enableSearch === undefined || config.enableSearch; resolve(this.siteConfig); }) - .catch((err) => { - reject(new Error(`Failed to read the site config file '${this.siteConfigPath}' at` - + `${this.rootPath}:\n${err.message}\nPlease ensure the file exist or is valid`)); + .catch(err => { + reject( + new Error( + `Failed to read the site config file '${this.siteConfigPath}' at` + + `${this.rootPath}:\n${ + err.message + }\nPlease ensure the file exist or is valid`, + ), + ); }); }); }; -Site.prototype.listAssets = function (fileIgnore) { +Site.prototype.listAssets = function(fileIgnore) { return new Promise((resolve, reject) => { let files; try { @@ -325,10 +372,13 @@ Site.prototype.listAssets = function (fileIgnore) { }); }; -Site.prototype.createPage = function (config) { +Site.prototype.createPage = function(config) { const sourcePath = path.join(this.rootPath, config.pageSrc); const tempPath = path.join(this.tempPath, config.pageSrc); - const resultPath = path.join(this.outputPath, setExtension(config.pageSrc, '.html')); + const resultPath = path.join( + this.outputPath, + setExtension(config.pageSrc, '.html'), + ); return new Page({ baseUrl: this.siteConfig.baseUrl, baseUrlMap: this.baseUrlMap, @@ -341,46 +391,84 @@ Site.prototype.createPage = function (config) { enableSearch: this.siteConfig.enableSearch, searchable: this.siteConfig.enableSearch && config.searchable, src: config.pageSrc, - layoutsAssetPath: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, LAYOUT_SITE_FOLDER_NAME)), + layoutsAssetPath: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, LAYOUT_SITE_FOLDER_NAME), + ), layout: config.layout, title: config.title || '', titlePrefix: this.siteConfig.titlePrefix, - headingIndexingLevel: this.siteConfig.headingIndexingLevel || HEADING_INDEXING_LEVEL_DEFAULT, + headingIndexingLevel: + this.siteConfig.headingIndexingLevel || HEADING_INDEXING_LEVEL_DEFAULT, userDefinedVariablesMap: this.userDefinedVariablesMap, sourcePath, tempPath, resultPath, asset: { - bootstrap: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'bootstrap.min.css')), - bootstrapVue: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'bootstrap-vue.min.css')), - externalScripts: _.union(this.siteConfig.externalScripts, config.externalScripts), - fontAwesome: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'font-awesome.min.css')), - glyphicons: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'bootstrap-glyphicons.min.css')), - highlight: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'github.min.css')), - markbind: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'markbind.css')), - pageNavCss: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'page-nav.css')), - siteNavCss: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'css', 'site-nav.css')), - bootstrapUtilityJs: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'bootstrap-utility.min.js')), - bootstrapVueJs: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'bootstrap-vue.min.js')), - polyfillJs: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'polyfill.min.js')), - setup: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'setup.js')), - vue: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'vue.min.js')), - vueStrap: path.relative(path.dirname(resultPath), - path.join(this.siteAssetsDestPath, 'js', 'vue-strap.min.js')), + bootstrap: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'bootstrap.min.css'), + ), + bootstrapVue: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'bootstrap-vue.min.css'), + ), + externalScripts: _.union( + this.siteConfig.externalScripts, + config.externalScripts, + ), + fontAwesome: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'font-awesome.min.css'), + ), + glyphicons: path.relative( + path.dirname(resultPath), + path.join( + this.siteAssetsDestPath, + 'css', + 'bootstrap-glyphicons.min.css', + ), + ), + highlight: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'github.min.css'), + ), + markbind: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'markbind.css'), + ), + pageNavCss: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'page-nav.css'), + ), + siteNavCss: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'css', 'site-nav.css'), + ), + bootstrapUtilityJs: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'bootstrap-utility.min.js'), + ), + bootstrapVueJs: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'bootstrap-vue.min.js'), + ), + polyfillJs: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'polyfill.min.js'), + ), + setup: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'setup.js'), + ), + vue: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'vue.min.js'), + ), + vueStrap: path.relative( + path.dirname(resultPath), + path.join(this.siteAssetsDestPath, 'js', 'vue-strap.min.js'), + ), }, }); }; @@ -388,18 +476,19 @@ Site.prototype.createPage = function (config) { /** * Updates the paths to be traversed as addressable pages and returns a list of filepaths to be deleted */ -Site.prototype.updateAddressablePages = function () { +Site.prototype.updateAddressablePages = function() { const oldAddressablePages = this.addressablePages.slice(); this.collectAddressablePages(); - return _.difference(oldAddressablePages.map(page => page.src), - this.addressablePages.map(page => page.src)) - .map(filePath => setExtension(filePath, '.html')); + return _.difference( + oldAddressablePages.map(page => page.src), + this.addressablePages.map(page => page.src), + ).map(filePath => setExtension(filePath, '.html')); }; /** * Collects the paths to be traversed as addressable pages */ -Site.prototype.collectAddressablePages = function () { +Site.prototype.collectAddressablePages = function() { const { pages } = this.siteConfig; const addressableGlobs = pages.filter(page => page.glob); this.addressablePages = pages.filter(page => page.src); @@ -409,21 +498,31 @@ Site.prototype.collectAddressablePages = function () { .map(page => page.src); if (duplicatePages.length > 0) { return Promise.reject( - new Error(`Duplicate page entries found in site config: ${_.uniq(duplicatePages).join(', ')}`)); + new Error( + `Duplicate page entries found in site config: ${_.uniq( + duplicatePages, + ).join(', ')}`, + ), + ); } - const globPaths = addressableGlobs.reduce((globPages, addressableGlob) => - globPages.concat(walkSync(this.rootPath, { - directories: false, - globs: [addressableGlob.glob], - ignore: [CONFIG_FOLDER_NAME], - }).map(globPath => ({ - src: globPath, - searchable: addressableGlob.searchable, - layout: addressableGlob.layout, - }))), []); + const globPaths = addressableGlobs.reduce( + (globPages, addressableGlob) => + globPages.concat( + walkSync(this.rootPath, { + directories: false, + globs: [addressableGlob.glob], + ignore: [CONFIG_FOLDER_NAME], + }).map(globPath => ({ + src: globPath, + searchable: addressableGlob.searchable, + layout: addressableGlob.layout, + })), + ), + [], + ); // Add pages collected by walkSync and merge properties for pages const filteredPages = {}; - globPaths.concat(this.addressablePages).forEach((page) => { + globPaths.concat(this.addressablePages).forEach(page => { const filteredPage = _.omitBy(page, _.isUndefined); if (page.src in filteredPages) { filteredPages[page.src] = { ...filteredPages[page.src], ...filteredPage }; @@ -436,11 +535,10 @@ Site.prototype.collectAddressablePages = function () { return Promise.resolve(); }; -Site.prototype.collectBaseUrl = function () { - const candidates - = walkSync(this.rootPath, { directories: false }) - .filter(x => x.endsWith(this.siteConfigPath)) - .map(x => path.resolve(this.rootPath, x)); +Site.prototype.collectBaseUrl = function() { + const candidates = walkSync(this.rootPath, { directories: false }) + .filter(x => x.endsWith(this.siteConfigPath)) + .map(x => path.resolve(this.rootPath, x)); this.baseUrlMap = candidates.reduce((pre, now) => { // eslint-disable-next-line no-param-reassign @@ -454,14 +552,14 @@ Site.prototype.collectBaseUrl = function () { /** * Collects the user defined variables map in the site/subsites */ -Site.prototype.collectUserDefinedVariablesMap = function () { +Site.prototype.collectUserDefinedVariablesMap = function() { // The key is the base directory of the site/subsites, // while the value is a mapping of user defined variables this.userDefinedVariablesMap = {}; const iconsMap = getIconsMap(); const markbindVariable = { MarkBind: MARKBIND_LINK_HTML }; - Object.keys(this.baseUrlMap).forEach((base) => { + Object.keys(this.baseUrlMap).forEach(base => { const userDefinedVariables = {}; Object.assign(userDefinedVariables, iconsMap, markbindVariable); @@ -480,12 +578,17 @@ Site.prototype.collectUserDefinedVariablesMap = function () { this.userDefinedVariablesMap[base] = userDefinedVariables; const $ = cheerio.load(content); - $.root().children().each(function () { - const id = $(this).attr('id'); - // Process the content of the variable with nunjucks, in case it refers to other variables. - const html = nunjucks.renderString($(this).html(), userDefinedVariables); - userDefinedVariables[id] = html; - }); + $.root() + .children() + .each(function() { + const id = $(this).attr('id'); + // Process the content of the variable with nunjucks, in case it refers to other variables. + const html = nunjucks.renderString( + $(this).html(), + userDefinedVariables, + ); + userDefinedVariables[id] = html; + }); }); }; @@ -494,7 +597,7 @@ Site.prototype.collectUserDefinedVariablesMap = function () { * if there is a change in the variables file * @param filePaths array of paths corresponding to files that have changed */ -Site.prototype.collectUserDefinedVariablesMapIfNeeded = function (filePaths) { +Site.prototype.collectUserDefinedVariablesMapIfNeeded = function(filePaths) { const variablesPath = path.resolve(this.rootPath, USER_VARIABLES_PATH); if (filePaths.includes(variablesPath)) { this.collectUserDefinedVariablesMap(); @@ -503,14 +606,16 @@ Site.prototype.collectUserDefinedVariablesMapIfNeeded = function (filePaths) { return false; }; -Site.prototype.generate = function (baseUrl) { +Site.prototype.generate = function(baseUrl) { const startTime = new Date(); // Create the .tmp folder for storing intermediate results. logger.profile(GENERATE_SITE_LOGGING_KEY); fs.emptydirSync(this.tempPath); // Clean the output folder; create it if not exist. fs.emptydirSync(this.outputPath); - logger.info(`Website generation started at ${startTime.toLocaleTimeString()}`); + logger.info( + `Website generation started at ${startTime.toLocaleTimeString()}`, + ); return new Promise((resolve, reject) => { this.readSiteConfig(baseUrl) .then(() => this.collectAddressablePages()) @@ -525,10 +630,12 @@ Site.prototype.generate = function (baseUrl) { .then(() => { const endTime = new Date(); const totalBuildTime = (endTime - startTime) / 1000; - logger.info(`Website generation complete! Total build time: ${totalBuildTime}s`); + logger.info( + `Website generation complete! Total build time: ${totalBuildTime}s`, + ); }) .then(resolve) - .catch((error) => { + .catch(error => { rejectHandler(reject, error, [this.tempPath, this.outputPath]); }) .finally(() => logger.profile(GENERATE_SITE_LOGGING_KEY)); @@ -538,21 +645,21 @@ Site.prototype.generate = function (baseUrl) { /** * Build all pages of the site */ -Site.prototype.buildSourceFiles = function () { +Site.prototype.buildSourceFiles = function() { return new Promise((resolve, reject) => { logger.info('Generating pages...'); this.generatePages() .then(() => fs.removeAsync(this.tempPath)) .then(() => logger.info('Pages built')) .then(resolve) - .catch((error) => { + .catch(error => { // if error, remove the site and temp folders rejectHandler(reject, error, [this.tempPath, this.outputPath]); }); }); }; -Site.prototype._rebuildAffectedSourceFiles = function (filePaths) { +Site.prototype._rebuildAffectedSourceFiles = function(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); logger.info('Rebuilding affected source files'); @@ -560,7 +667,7 @@ Site.prototype._rebuildAffectedSourceFiles = function (filePaths) { this.regenerateAffectedPages(uniquePaths) .then(() => fs.removeAsync(this.tempPath)) .then(resolve) - .catch((error) => { + .catch(error => { // if error, remove the site and temp folders rejectHandler(reject, error, [this.tempPath, this.outputPath]); }); @@ -571,10 +678,12 @@ Site.prototype._rebuildAffectedSourceFiles = function (filePaths) { * Rebuild pages that are affected by changes in filePaths * @param filePaths a single path or an array of paths corresponding to the files that have changed */ -Site.prototype.rebuildAffectedSourceFiles - = delay(Site.prototype._rebuildAffectedSourceFiles, 1000); +Site.prototype.rebuildAffectedSourceFiles = delay( + Site.prototype._rebuildAffectedSourceFiles, + 1000, +); -Site.prototype._rebuildSourceFiles = function () { +Site.prototype._rebuildSourceFiles = function() { logger.warn('Rebuilding all source files'); return new Promise((resolve, reject) => { Promise.resolve('') @@ -582,7 +691,7 @@ Site.prototype._rebuildSourceFiles = function () { .then(filesToRemove => this.removeAsset(filesToRemove)) .then(() => this.buildSourceFiles()) .then(resolve) - .catch((error) => { + .catch(error => { // if error, remove the site and temp folders rejectHandler(reject, error, [this.tempPath, this.outputPath]); }); @@ -593,47 +702,56 @@ Site.prototype._rebuildSourceFiles = function () { * Rebuild all pages * @param filePaths a single path or an array of paths corresponding to the files that have changed */ -Site.prototype.rebuildSourceFiles - = delay(Site.prototype._rebuildSourceFiles, 1000); +Site.prototype.rebuildSourceFiles = delay( + Site.prototype._rebuildSourceFiles, + 1000, +); -Site.prototype._buildMultipleAssets = function (filePaths) { +Site.prototype._buildMultipleAssets = function(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); const ignoreConfig = this.siteConfig.ignore || []; const fileIgnore = ignore().add(ignoreConfig); - const fileRelativePaths = uniquePaths.map(filePath => path.relative(this.rootPath, filePath)); - const copyAssets = fileIgnore.filter(fileRelativePaths) - .map(asset => fs.copyAsync(path.join(this.rootPath, asset), path.join(this.outputPath, asset))); - return Promise.all(copyAssets) - .then(() => logger.info('Assets built')); + const fileRelativePaths = uniquePaths.map(filePath => + path.relative(this.rootPath, filePath), + ); + const copyAssets = fileIgnore + .filter(fileRelativePaths) + .map(asset => + fs.copyAsync( + path.join(this.rootPath, asset), + path.join(this.outputPath, asset), + ), + ); + return Promise.all(copyAssets).then(() => logger.info('Assets built')); }; /** * Build/copy assets that are specified in filePaths * @param filePaths a single path or an array of paths corresponding to the assets to build */ -Site.prototype.buildAsset - = delay(Site.prototype._buildMultipleAssets, 1000); +Site.prototype.buildAsset = delay(Site.prototype._buildMultipleAssets, 1000); -Site.prototype._removeMultipleAssets = function (filePaths) { +Site.prototype._removeMultipleAssets = function(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); - const fileRelativePaths = uniquePaths.map(filePath => path.relative(this.rootPath, filePath)); - const filesToRemove = fileRelativePaths.map( - fileRelativePath => path.join(this.outputPath, fileRelativePath)); + const fileRelativePaths = uniquePaths.map(filePath => + path.relative(this.rootPath, filePath), + ); + const filesToRemove = fileRelativePaths.map(fileRelativePath => + path.join(this.outputPath, fileRelativePath), + ); const removeFiles = filesToRemove.map(asset => fs.removeAsync(asset)); - return Promise.all(removeFiles) - .then(() => logger.info('Assets removed')); + return Promise.all(removeFiles).then(() => logger.info('Assets removed')); }; /** * Remove assets that are specified in filePaths * @param filePaths a single path or an array of paths corresponding to the assets to remove */ -Site.prototype.removeAsset - = delay(Site.prototype._removeMultipleAssets, 1000); +Site.prototype.removeAsset = delay(Site.prototype._removeMultipleAssets, 1000); -Site.prototype.buildAssets = function () { +Site.prototype.buildAssets = function() { logger.info('Building assets...'); return new Promise((resolve, reject) => { const ignoreConfig = this.siteConfig.ignore || []; @@ -643,12 +761,17 @@ Site.prototype.buildAssets = function () { // Scan and copy assets (excluding ignore files). this.listAssets(fileIgnore) .then(assets => - assets.map(asset => fs.copyAsync(path.join(this.rootPath, asset), path.join(this.outputPath, asset))), + assets.map(asset => + fs.copyAsync( + path.join(this.rootPath, asset), + path.join(this.outputPath, asset), + ), + ), ) .then(copyAssets => Promise.all(copyAssets)) .then(() => logger.info('Assets built')) .then(resolve) - .catch((error) => { + .catch(error => { rejectHandler(reject, error, []); // assets won't affect deletion }); }); @@ -660,13 +783,21 @@ Site.prototype.buildAssets = function () { */ function getPluginPath(rootPath, plugin) { // Check in project folder - const pluginPath = path.join(rootPath, PROJECT_PLUGIN_FOLDER_NAME, `${plugin}.js`); + const pluginPath = path.join( + rootPath, + PROJECT_PLUGIN_FOLDER_NAME, + `${plugin}.js`, + ); if (fs.existsSync(pluginPath)) { return pluginPath; } // Check in src folder - const defaultPath = path.join(__dirname, BUILT_IN_PLUGIN_FOLDER_NAME, `${plugin}.js`); + const defaultPath = path.join( + __dirname, + BUILT_IN_PLUGIN_FOLDER_NAME, + `${plugin}.js`, + ); if (fs.existsSync(defaultPath)) { return defaultPath; } @@ -677,12 +808,12 @@ function getPluginPath(rootPath, plugin) { /** * Load all plugins of the site */ -Site.prototype.collectPlugins = function () { +Site.prototype.collectPlugins = function() { if (!this.siteConfig.plugins) { return; } module.paths.push(path.join(this.rootPath, 'node_modules')); - this.siteConfig.plugins.forEach((plugin) => { + this.siteConfig.plugins.forEach(plugin => { try { const pluginPath = getPluginPath(this.rootPath, plugin); @@ -697,7 +828,7 @@ Site.prototype.collectPlugins = function () { /** * Renders all pages specified in site configuration file to the output folder */ -Site.prototype.generatePages = function () { +Site.prototype.generatePages = function() { // Run MarkBind include and render on each source file. // Render the final rendered page to the output folder. const { baseUrl, faviconPath } = this.siteConfig; @@ -719,37 +850,52 @@ Site.prototype.generatePages = function () { if (this.onePagePath) { const page = addressablePages.find(p => p.src === this.onePagePath); if (!page) { - return Promise.reject(new Error(`${this.onePagePath} is not specified in the site configuration.`)); + return Promise.reject( + new Error( + `${this.onePagePath} is not specified in the site configuration.`, + ), + ); } - this.pages.push(this.createPage({ - faviconUrl, - pageSrc: page.src, - title: page.title, - layout: page.layout, - searchable: page.searchable !== 'no', - externalScripts: page.externalScripts, - })); + this.pages.push( + this.createPage({ + faviconUrl, + pageSrc: page.src, + title: page.title, + layout: page.layout, + searchable: page.searchable !== 'no', + externalScripts: page.externalScripts, + }), + ); } else { - this.pages = addressablePages.map(page => this.createPage({ - faviconUrl, - pageSrc: page.src, - title: page.title, - layout: page.layout, - searchable: page.searchable !== 'no', - externalScripts: page.externalScripts, - })); + this.pages = addressablePages.map(page => + this.createPage({ + faviconUrl, + pageSrc: page.src, + title: page.title, + layout: page.layout, + searchable: page.searchable !== 'no', + externalScripts: page.externalScripts, + }), + ); } - const progressBar = new ProgressBar(`[:bar] :current / ${this.pages.length} pages built`, - { total: this.pages.length }); + const progressBar = new ProgressBar( + `[:bar] :current / ${this.pages.length} pages built`, + { total: this.pages.length }, + ); progressBar.render(); - this.pages.forEach((page) => { - processingFiles.push(page.generate(builtFiles) - .then(() => progressBar.tick()) - .catch((err) => { - logger.error(err); - return Promise.reject(new Error(`Error while generating ${page.sourcePath}`)); - })); + this.pages.forEach(page => { + processingFiles.push( + page + .generate(builtFiles) + .then(() => progressBar.tick()) + .catch(err => { + logger.error(err); + return Promise.reject( + new Error(`Error while generating ${page.sourcePath}`), + ); + }), + ); }); return new Promise((resolve, reject) => { Promise.all(processingFiles) @@ -763,23 +909,32 @@ Site.prototype.generatePages = function () { * as the source file or as a static/dynamic included file * @param filePaths array of paths corresponding to files that have changed */ -Site.prototype.regenerateAffectedPages = function (filePaths) { +Site.prototype.regenerateAffectedPages = function(filePaths) { const builtFiles = {}; const processingFiles = []; - const shouldRebuildAllPages = this.collectUserDefinedVariablesMapIfNeeded(filePaths) || this.forceReload; + const shouldRebuildAllPages = + this.collectUserDefinedVariablesMapIfNeeded(filePaths) || this.forceReload; if (shouldRebuildAllPages) { - logger.warn('Rebuilding all pages as variables file was changed, or the --force-reload flag was set'); + logger.warn( + 'Rebuilding all pages as variables file was changed, or the --force-reload flag was set', + ); } this._setTimestampVariable(); - this.pages.forEach((page) => { - if (shouldRebuildAllPages || filePaths.some(filePath => page.includedFiles[filePath])) { + this.pages.forEach(page => { + if ( + shouldRebuildAllPages || + filePaths.some(filePath => page.includedFiles[filePath]) + ) { // eslint-disable-next-line no-param-reassign page.userDefinedVariablesMap = this.userDefinedVariablesMap; - processingFiles.push(page.generate(builtFiles) - .catch((err) => { + processingFiles.push( + page.generate(builtFiles).catch(err => { logger.error(err); - return Promise.reject(new Error(`Error while generating ${page.sourcePath}`)); - })); + return Promise.reject( + new Error(`Error while generating ${page.sourcePath}`), + ); + }), + ); } }); @@ -787,24 +942,28 @@ Site.prototype.regenerateAffectedPages = function (filePaths) { return new Promise((resolve, reject) => { Promise.all(processingFiles) - .then(() => this.updateSiteData(shouldRebuildAllPages ? undefined : filePaths)) + .then(() => + this.updateSiteData(shouldRebuildAllPages ? undefined : filePaths), + ) .then(() => logger.info('Pages rebuilt')) .then(resolve) .catch(reject); }); }; - /** * Uses heading data in built pages to generate heading and keyword information for siteData * Subsequently writes to siteData.json * @param filePaths optional array of updated file paths during live preview. * If undefined, generate site data for all pages */ -Site.prototype.updateSiteData = function (filePaths) { +Site.prototype.updateSiteData = function(filePaths) { const generateForAllPages = filePaths === undefined; - this.pages.forEach((page) => { - if (generateForAllPages || filePaths.some(filePath => page.includedFiles[filePath])) { + this.pages.forEach(page => { + if ( + generateForAllPages || + filePaths.some(filePath => page.includedFiles[filePath]) + ) { page.collectHeadingsAndKeywords(); page.concatenateHeadingsAndKeywords(); } @@ -812,7 +971,7 @@ Site.prototype.updateSiteData = function (filePaths) { this.writeSiteData(); }; -Site.prototype.copyMarkBindAsset = function () { +Site.prototype.copyMarkBindAsset = function() { return new Promise((resolve, reject) => { fs.copyAsync(this.siteAssetsSrcPath, this.siteAssetsDestPath) .then(resolve) @@ -823,9 +982,12 @@ Site.prototype.copyMarkBindAsset = function () { /** * Copies layouts to the assets folder */ -Site.prototype.copyLayouts = function () { +Site.prototype.copyLayouts = function() { const siteLayoutPath = path.join(this.rootPath, LAYOUT_FOLDER_PATH); - const layoutsDestPath = path.join(this.siteAssetsDestPath, LAYOUT_SITE_FOLDER_NAME); + const layoutsDestPath = path.join( + this.siteAssetsDestPath, + LAYOUT_SITE_FOLDER_NAME, + ); if (!fs.existsSync(siteLayoutPath)) { return Promise.resolve(); } @@ -839,25 +1001,28 @@ Site.prototype.copyLayouts = function () { /** * Writes the site data to a file */ -Site.prototype.writeSiteData = function () { +Site.prototype.writeSiteData = function() { return new Promise((resolve, reject) => { const siteDataPath = path.join(this.outputPath, SITE_DATA_NAME); const siteData = { enableSearch: this.siteConfig.enableSearch, - pages: this.pages.filter(page => page.searchable) - .map(page => Object.assign({ headings: page.headings }, page.frontMatter)), + pages: this.pages + .filter(page => page.searchable) + .map(page => + Object.assign({ headings: page.headings }, page.frontMatter), + ), }; fs.outputJsonAsync(siteDataPath, siteData) .then(() => logger.info('Site data built')) .then(resolve) - .catch((error) => { + .catch(error => { rejectHandler(reject, error, [this.tempPath, this.outputPath]); }); }); }; -Site.prototype.deploy = function (travisTokenVar) { +Site.prototype.deploy = function(travisTokenVar) { const defaultDeployConfig = { branch: 'gh-pages', message: 'Site Update.', @@ -871,12 +1036,18 @@ Site.prototype.deploy = function (travisTokenVar) { this.siteConfig.deploy = this.siteConfig.deploy || {}; const basePath = this.siteConfig.deploy.baseDir || this.outputPath; if (!fs.existsSync(basePath)) { - reject(new Error('The site directory does not exist. Please build the site first before deploy.')); + reject( + new Error( + 'The site directory does not exist. Please build the site first before deploy.', + ), + ); return undefined; } const options = {}; - options.branch = this.siteConfig.deploy.branch || defaultDeployConfig.branch; - options.message = this.siteConfig.deploy.message || defaultDeployConfig.message; + options.branch = + this.siteConfig.deploy.branch || defaultDeployConfig.branch; + options.message = + this.siteConfig.deploy.message || defaultDeployConfig.message; options.repo = this.siteConfig.deploy.repo || defaultDeployConfig.repo; if (travisTokenVar) { @@ -885,9 +1056,15 @@ Site.prototype.deploy = function (travisTokenVar) { return undefined; } // eslint-disable-next-line no-param-reassign - travisTokenVar = _.isBoolean(travisTokenVar) ? 'GITHUB_TOKEN' : travisTokenVar; + travisTokenVar = _.isBoolean(travisTokenVar) + ? 'GITHUB_TOKEN' + : travisTokenVar; if (!process.env[travisTokenVar]) { - reject(new Error(`The environment variable ${travisTokenVar} does not exist.`)); + reject( + new Error( + `The environment variable ${travisTokenVar} does not exist.`, + ), + ); return undefined; } @@ -898,8 +1075,12 @@ Site.prototype.deploy = function (travisTokenVar) { const repoSlugRegex = /github\.com[:/]([\w-]+\/[\w-.]+)\.git$/; const repoSlugMatch = repoSlugRegex.exec(options.repo); if (!repoSlugMatch) { - reject(new Error('-t/--travis expects a GitHub repository.\n' - + `The specified repository ${options.repo} is not valid.`)); + reject( + new Error( + '-t/--travis expects a GitHub repository.\n' + + `The specified repository ${options.repo} is not valid.`, + ), + ); return undefined; } [, repoSlug] = repoSlugMatch; @@ -918,9 +1099,9 @@ Site.prototype.deploy = function (travisTokenVar) { }); }; -Site.prototype._setTimestampVariable = function () { +Site.prototype._setTimestampVariable = function() { const time = new Date().toUTCString(); - Object.keys(this.userDefinedVariablesMap).forEach((base) => { + Object.keys(this.userDefinedVariablesMap).forEach(base => { this.userDefinedVariablesMap[base].timestamp = time; }); return Promise.resolve(); diff --git a/src/__mocks__/Page.js b/src/__mocks__/Page.js index d038ace738..e95e502a3b 100644 --- a/src/__mocks__/Page.js +++ b/src/__mocks__/Page.js @@ -4,5 +4,4 @@ const Page = jest.genMockFromModule('../Page'); Page.prototype.generate = () => Promise.resolve(''); - module.exports = Page; diff --git a/src/lib/markbind/src/handlers/cyclicReferenceError.js b/src/lib/markbind/src/handlers/cyclicReferenceError.js index 9d7f04c461..48207ae130 100644 --- a/src/lib/markbind/src/handlers/cyclicReferenceError.js +++ b/src/lib/markbind/src/handlers/cyclicReferenceError.js @@ -2,8 +2,9 @@ class CyclicReferenceError extends Error { constructor(callStack) { super(); const fileStack = callStack.slice(Math.max(callStack.length - 5, 0)); - this.message = 'Cyclic reference detected.\n' - + `Last 5 files processed:${'\n\t'}${fileStack.join('\n\t')}`; + this.message = + 'Cyclic reference detected.\n' + + `Last 5 files processed:${'\n\t'}${fileStack.join('\n\t')}`; } } CyclicReferenceError.MAX_RECURSIVE_DEPTH = 200; diff --git a/src/lib/markbind/src/parser.js b/src/lib/markbind/src/parser.js index 5f93a42e4e..aae61d357e 100644 --- a/src/lib/markbind/src/parser.js +++ b/src/lib/markbind/src/parser.js @@ -32,11 +32,13 @@ const BOILERPLATE_FOLDER_NAME = '_markbind/boilerplates'; */ /** -* @throws Will throw an error if a non-absolute path or path outside the root is given -*/ + * @throws Will throw an error if a non-absolute path or path outside the root is given + */ function calculateNewBaseUrls(filePath, root, lookUp) { if (!path.isAbsolute(filePath)) { - throw new Error(`Non-absolute path given to calculateNewBaseUrls: '${filePath}'`); + throw new Error( + `Non-absolute path given to calculateNewBaseUrls: '${filePath}'`, + ); } if (!pathIsInside(filePath, root)) { throw new Error(`Path given '${filePath}' is not in root '${root}'`); @@ -58,13 +60,28 @@ function calculateNewBaseUrls(filePath, root, lookUp) { } function calculateBoilerplateFilePath(pathInBoilerplates, asIfAt, config) { - const { parent, relative } = calculateNewBaseUrls(asIfAt, config.rootPath, config.baseUrlMap); - return path.resolve(parent, relative, BOILERPLATE_FOLDER_NAME, pathInBoilerplates); + const { parent, relative } = calculateNewBaseUrls( + asIfAt, + config.rootPath, + config.baseUrlMap, + ); + return path.resolve( + parent, + relative, + BOILERPLATE_FOLDER_NAME, + pathInBoilerplates, + ); } function createErrorNode(element, error) { - const errorElement = cheerio.parseHTML(utils.createErrorElement(error), true)[0]; - return Object.assign(element, _.pick(errorElement, ['name', 'attribs', 'children'])); + const errorElement = cheerio.parseHTML( + utils.createErrorElement(error), + true, + )[0]; + return Object.assign( + element, + _.pick(errorElement, ['name', 'attribs', 'children']), + ); } function createEmptyNode() { @@ -94,7 +111,7 @@ function Parser(options) { */ function extractIncludeVariables(includeElement, contextVariables) { const includedVariables = { ...contextVariables }; - Object.keys(includeElement.attribs).forEach((attribute) => { + Object.keys(includeElement.attribs).forEach(attribute => { if (!attribute.startsWith('var-')) { return; } @@ -104,14 +121,18 @@ function extractIncludeVariables(includeElement, contextVariables) { } }); if (includeElement.children) { - includeElement.children.forEach((child) => { + includeElement.children.forEach(child => { if (child.name !== 'span') { return; } if (!child.attribs.id) { // eslint-disable-next-line no-console - console.warn(`Missing reference in ${includeElement.attribs[ATTRIB_CWF]}\n` - + `Missing 'id' in variable for ${includeElement.attribs.src} include.`); + console.warn( + `Missing reference in ${includeElement.attribs[ATTRIB_CWF]}\n` + + `Missing 'id' in variable for ${ + includeElement.attribs.src + } include.`, + ); return; } if (!includedVariables[child.attribs.id]) { @@ -129,10 +150,15 @@ function extractIncludeVariables(includeElement, contextVariables) { * @param userDefinedVariables global variables * @param includedVariables variables from parent include */ -function extractPageVariables(fileName, data, userDefinedVariables, includedVariables) { +function extractPageVariables( + fileName, + data, + userDefinedVariables, + includedVariables, +) { const $ = cheerio.load(data); - const pageVariables = { }; - $('variable').each(function () { + const pageVariables = {}; + $('variable').each(function() { const variableElement = $(this); const variableName = variableElement.attr('name'); if (!variableName) { @@ -141,31 +167,32 @@ function extractPageVariables(fileName, data, userDefinedVariables, includedVari return; } if (!pageVariables[variableName]) { - pageVariables[variableName] - = nunjucks.renderString(md.renderInline(variableElement.html()), - { ...pageVariables, ...userDefinedVariables, ...includedVariables }); + pageVariables[variableName] = nunjucks.renderString( + md.renderInline(variableElement.html()), + { ...pageVariables, ...userDefinedVariables, ...includedVariables }, + ); } }); return pageVariables; } -Parser.prototype.getDynamicIncludeSrc = function () { +Parser.prototype.getDynamicIncludeSrc = function() { return _.clone(this.dynamicIncludeSrc); }; -Parser.prototype.getStaticIncludeSrc = function () { +Parser.prototype.getStaticIncludeSrc = function() { return _.clone(this.staticIncludeSrc); }; -Parser.prototype.getBoilerplateIncludeSrc = function () { +Parser.prototype.getBoilerplateIncludeSrc = function() { return _.clone(this.boilerplateIncludeSrc); }; -Parser.prototype.getMissingIncludeSrc = function () { +Parser.prototype.getMissingIncludeSrc = function() { return _.clone(this.missingIncludeSrc); }; -Parser.prototype._preprocess = function (node, context, config) { +Parser.prototype._preprocess = function(node, context, config) { const element = node; const self = this; element.attribs = element.attribs || {}; @@ -173,7 +200,11 @@ Parser.prototype._preprocess = function (node, context, config) { const requiresSrc = ['include'].includes(element.name); if (requiresSrc && _.isEmpty(element.attribs.src)) { - const error = new Error(`Empty src attribute in ${element.name} in: ${element.attribs[ATTRIB_CWF]}`); + const error = new Error( + `Empty src attribute in ${element.name} in: ${ + element.attribs[ATTRIB_CWF] + }`, + ); this._onError(error); return createErrorNode(element, error); } @@ -189,22 +220,36 @@ Parser.prototype._preprocess = function (node, context, config) { includeSrc = url.parse(element.attribs.src); filePath = isUrl ? element.attribs.src - : path.resolve(path.dirname(context.cwf), decodeURIComponent(includeSrc.path)); + : path.resolve( + path.dirname(context.cwf), + decodeURIComponent(includeSrc.path), + ); actualFilePath = filePath; const isBoilerplate = _.hasIn(element.attribs, 'boilerplate'); if (isBoilerplate) { - element.attribs.boilerplate = element.attribs.boilerplate || path.basename(filePath); - actualFilePath = calculateBoilerplateFilePath(element.attribs.boilerplate, filePath, config); - this.boilerplateIncludeSrc.push({ from: context.cwf, to: actualFilePath }); + element.attribs.boilerplate = + element.attribs.boilerplate || path.basename(filePath); + actualFilePath = calculateBoilerplateFilePath( + element.attribs.boilerplate, + filePath, + config, + ); + this.boilerplateIncludeSrc.push({ + from: context.cwf, + to: actualFilePath, + }); } - const isOptional = element.name === 'include' && _.hasIn(element.attribs, 'optional'); + const isOptional = + element.name === 'include' && _.hasIn(element.attribs, 'optional'); if (!utils.fileExists(actualFilePath)) { if (isOptional) { return createEmptyNode(); } this.missingIncludeSrc.push({ from: context.cwf, to: actualFilePath }); const error = new Error( - `No such file: ${actualFilePath}\nMissing reference in ${element.attribs[ATTRIB_CWF]}`, + `No such file: ${actualFilePath}\nMissing reference in ${ + element.attribs[ATTRIB_CWF] + }`, ); this._onError(error); return createErrorNode(element, error); @@ -235,7 +280,11 @@ Parser.prototype._preprocess = function (node, context, config) { element.attribs.header = element.attribs.name || ''; delete element.attribs.dynamic; - this.dynamicIncludeSrc.push({ from: context.cwf, to: actualFilePath, asIfTo: element.attribs.src }); + this.dynamicIncludeSrc.push({ + from: context.cwf, + to: actualFilePath, + asIfTo: element.attribs.src, + }); return element; } @@ -247,10 +296,13 @@ Parser.prototype._preprocess = function (node, context, config) { try { self._fileCache[actualFilePath] = self._fileCache[actualFilePath] - ? self._fileCache[actualFilePath] : fs.readFileSync(actualFilePath, 'utf8'); + ? self._fileCache[actualFilePath] + : fs.readFileSync(actualFilePath, 'utf8'); } catch (e) { // Read file fail - const missingReferenceErrorMessage = `Missing reference in: ${element.attribs[ATTRIB_CWF]}`; + const missingReferenceErrorMessage = `Missing reference in: ${ + element.attribs[ATTRIB_CWF] + }`; e.message += `\n${missingReferenceErrorMessage}`; this._onError(e); return createErrorNode(element, e); @@ -264,23 +316,37 @@ Parser.prototype._preprocess = function (node, context, config) { } let fileContent = self._fileCache[actualFilePath]; // cache the file contents to save some I/O - const { parent, relative } = calculateNewBaseUrls(filePath, config.rootPath, config.baseUrlMap); - const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)]; + const { parent, relative } = calculateNewBaseUrls( + filePath, + config.rootPath, + config.baseUrlMap, + ); + const userDefinedVariables = + config.userDefinedVariablesMap[path.resolve(parent, relative)]; // Extract included variables from the PARENT file - const includeVariables = extractIncludeVariables(element, context.variables); + const includeVariables = extractIncludeVariables( + element, + context.variables, + ); // Extract page variables from the CHILD file - const pageVariables = extractPageVariables(element.attribs.src, fileContent, - userDefinedVariables, includeVariables); + const pageVariables = extractPageVariables( + element.attribs.src, + fileContent, + userDefinedVariables, + includeVariables, + ); // Render inner file content - fileContent = nunjucks.renderString(fileContent, - { ...pageVariables, ...includeVariables, ...userDefinedVariables }, - { path: actualFilePath }); + fileContent = nunjucks.renderString( + fileContent, + { ...pageVariables, ...includeVariables, ...userDefinedVariables }, + { path: actualFilePath }, + ); // Delete variable attributes in include - Object.keys(element.attribs).forEach((attribute) => { + Object.keys(element.attribs).forEach(attribute => { if (attribute.startsWith('var-')) { delete element.attribs[attribute]; } @@ -306,8 +372,10 @@ Parser.prototype._preprocess = function (node, context, config) { actualContent = ''; } else { const error = new Error( - `No such segment '${includeSrc.hash.substring(1)}' in file: ${actualFilePath}` - + `\nMissing reference in ${element.attribs[ATTRIB_CWF]}`, + `No such segment '${includeSrc.hash.substring( + 1, + )}' in file: ${actualFilePath}` + + `\nMissing reference in ${element.attribs[ATTRIB_CWF]}`, ); this._onError(error); return createErrorNode(element, error); @@ -321,18 +389,26 @@ Parser.prototype._preprocess = function (node, context, config) { if (isIncludeSrcMd) { if (context.mode === 'include') { - actualContent = isInline ? actualContent : utils.wrapContent(actualContent, '\n\n', '\n'); + actualContent = isInline + ? actualContent + : utils.wrapContent(actualContent, '\n\n', '\n'); } else { actualContent = md.render(actualContent); } - actualContent = self._rebaseReferenceForStaticIncludes(actualContent, element, config); + actualContent = self._rebaseReferenceForStaticIncludes( + actualContent, + element, + config, + ); } element.children = cheerio.parseHTML(actualContent, true); // the needed content; } else { let actualContent = fileContent; if (isIncludeSrcMd) { if (context.mode === 'include') { - actualContent = isInline ? actualContent : utils.wrapContent(actualContent, '\n\n', '\n'); + actualContent = isInline + ? actualContent + : utils.wrapContent(actualContent, '\n\n', '\n'); } else { actualContent = md.render(actualContent); } @@ -349,36 +425,50 @@ Parser.prototype._preprocess = function (node, context, config) { childContext.variables = includeVariables; if (element.children && element.children.length > 0) { - if (childContext.callStack.length > CyclicReferenceError.MAX_RECURSIVE_DEPTH) { + if ( + childContext.callStack.length > CyclicReferenceError.MAX_RECURSIVE_DEPTH + ) { const error = new CyclicReferenceError(childContext.callStack); this._onError(error); return createErrorNode(element, error); } - element.children = element.children.map(e => self._preprocess(e, childContext, config)); + element.children = element.children.map(e => + self._preprocess(e, childContext, config), + ); } - } else if ((element.name === 'panel') && hasSrc) { + } else if (element.name === 'panel' && hasSrc) { if (!isUrl && includeSrc.hash) { element.attribs.fragment = includeSrc.hash.substring(1); // save hash to fragment attribute } element.attribs.src = filePath; - this.dynamicIncludeSrc.push({ from: context.cwf, to: actualFilePath, asIfTo: filePath }); + this.dynamicIncludeSrc.push({ + from: context.cwf, + to: actualFilePath, + asIfTo: filePath, + }); return element; } else if (element.name === 'variable') { return createEmptyNode(); } else { if (element.name === 'body') { // eslint-disable-next-line no-console - console.warn(` tag found in ${element.attribs[ATTRIB_CWF]}. This may cause formatting errors.`); + console.warn( + ` tag found in ${ + element.attribs[ATTRIB_CWF] + }. This may cause formatting errors.`, + ); } if (element.children && element.children.length > 0) { - element.children = element.children.map(e => self._preprocess(e, context, config)); + element.children = element.children.map(e => + self._preprocess(e, context, config), + ); } } return element; }; -Parser.prototype._parse = function (node, context, config) { +Parser.prototype._parse = function(node, context, config) { const element = node; const self = this; if (_.isArray(element)) { @@ -393,40 +483,60 @@ Parser.prototype._parse = function (node, context, config) { } switch (element.name) { - case 'md': - element.name = 'span'; - cheerio.prototype.options.xmlMode = false; - element.children = cheerio.parseHTML(md.renderInline(cheerio.html(element.children)), true); - cheerio.prototype.options.xmlMode = true; - break; - case 'markdown': - element.name = 'div'; - cheerio.prototype.options.xmlMode = false; - element.children = cheerio.parseHTML(md.render(cheerio.html(element.children)), true); - cheerio.prototype.options.xmlMode = true; - break; - case 'panel': { - if (!_.hasIn(element.attribs, 'src')) { // dynamic panel + case 'md': + element.name = 'span'; + cheerio.prototype.options.xmlMode = false; + element.children = cheerio.parseHTML( + md.renderInline(cheerio.html(element.children)), + true, + ); + cheerio.prototype.options.xmlMode = true; + break; + case 'markdown': + element.name = 'div'; + cheerio.prototype.options.xmlMode = false; + element.children = cheerio.parseHTML( + md.render(cheerio.html(element.children)), + true, + ); + cheerio.prototype.options.xmlMode = true; + break; + case 'panel': { + if (!_.hasIn(element.attribs, 'src')) { + // dynamic panel + break; + } + const fileExists = + utils.fileExists(element.attribs.src) || + utils.fileExists( + calculateBoilerplateFilePath( + element.attribs.boilerplate, + element.attribs.src, + config, + ), + ); + if (fileExists) { + const { src, fragment } = element.attribs; + const resultDir = path.dirname( + path.join('{{hostBaseUrl}}', path.relative(config.rootPath, src)), + ); + const resultPath = path.join( + resultDir, + utils.setExtension(path.basename(src), '._include_.html'), + ); + element.attribs.src = utils.ensurePosix( + fragment ? `${resultPath}#${fragment}` : resultPath, + ); + } + delete element.attribs.boilerplate; break; } - const fileExists = utils.fileExists(element.attribs.src) - || utils.fileExists(calculateBoilerplateFilePath(element.attribs.boilerplate, - element.attribs.src, config)); - if (fileExists) { - const { src, fragment } = element.attribs; - const resultDir = path.dirname(path.join('{{hostBaseUrl}}', path.relative(config.rootPath, src))); - const resultPath = path.join(resultDir, utils.setExtension(path.basename(src), '._include_.html')); - element.attribs.src = utils.ensurePosix(fragment ? `${resultPath}#${fragment}` : resultPath); - } - delete element.attribs.boilerplate; - break; - } - default: - break; + default: + break; } if (element.children) { - element.children.forEach((child) => { + element.children.forEach(child => { self._parse(child, context, config); }); } @@ -434,7 +544,7 @@ Parser.prototype._parse = function (node, context, config) { return element; }; -Parser.prototype._trimNodes = function (node) { +Parser.prototype._trimNodes = function(node) { const self = this; if (node.name === 'pre' || node.name === 'code') { return; @@ -444,8 +554,10 @@ Parser.prototype._trimNodes = function (node) { for (let n = 0; n < node.children.length; n++) { const child = node.children[n]; if ( - child.type === 'comment' - || (child.type === 'text' && n === node.children.length - 1 && !/\S/.test(child.data)) + child.type === 'comment' || + (child.type === 'text' && + n === node.children.length - 1 && + !/\S/.test(child.data)) ) { node.children.splice(n, 1); n--; @@ -457,7 +569,7 @@ Parser.prototype._trimNodes = function (node) { } }; -Parser.prototype.includeFile = function (file, config) { +Parser.prototype.includeFile = function(file, config) { const context = {}; context.cwf = config.cwf || file; // current working file context.mode = 'include'; @@ -469,7 +581,7 @@ Parser.prototype.includeFile = function (file, config) { reject(error); return; } - const nodes = dom.map((d) => { + const nodes = dom.map(d => { let processed; try { processed = this._preprocess(d, context, config); @@ -490,7 +602,11 @@ Parser.prototype.includeFile = function (file, config) { let actualFilePath = file; if (!utils.fileExists(file)) { - const boilerplateFilePath = calculateBoilerplateFilePath(path.basename(file), file, config); + const boilerplateFilePath = calculateBoilerplateFilePath( + path.basename(file), + file, + config, + ); if (utils.fileExists(boilerplateFilePath)) { actualFilePath = boilerplateFilePath; } @@ -502,12 +618,24 @@ Parser.prototype.includeFile = function (file, config) { reject(err); return; } - const { parent, relative } = calculateNewBaseUrls(file, config.rootPath, config.baseUrlMap); - const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)]; - const pageVariables = extractPageVariables(path.basename(file), data, userDefinedVariables, {}); - const fileContent = nunjucks.renderString(data, - { ...pageVariables, ...userDefinedVariables }, - { path: actualFilePath }); + const { parent, relative } = calculateNewBaseUrls( + file, + config.rootPath, + config.baseUrlMap, + ); + const userDefinedVariables = + config.userDefinedVariablesMap[path.resolve(parent, relative)]; + const pageVariables = extractPageVariables( + path.basename(file), + data, + userDefinedVariables, + {}, + ); + const fileContent = nunjucks.renderString( + data, + { ...pageVariables, ...userDefinedVariables }, + { path: actualFilePath }, + ); const fileExt = utils.getExt(file); if (utils.isMarkdownFileExt(fileExt)) { context.source = 'md'; @@ -523,7 +651,7 @@ Parser.prototype.includeFile = function (file, config) { }); }; -Parser.prototype.renderFile = function (file, config) { +Parser.prototype.renderFile = function(file, config) { const context = {}; context.cwf = file; // current working file context.mode = 'render'; @@ -533,7 +661,7 @@ Parser.prototype.renderFile = function (file, config) { reject(error); return; } - const nodes = dom.map((d) => { + const nodes = dom.map(d => { let parsed; try { parsed = this._parse(d, context, config); @@ -544,7 +672,7 @@ Parser.prototype.renderFile = function (file, config) { } return parsed; }); - nodes.forEach((d) => { + nodes.forEach(d => { this._trimNodes(d); }); cheerio.prototype.options.xmlMode = false; @@ -579,7 +707,7 @@ Parser.prototype.renderFile = function (file, config) { }); }; -Parser.prototype.resolveBaseUrl = function (pageData, config) { +Parser.prototype.resolveBaseUrl = function(pageData, config) { const { baseUrlMap, rootPath, isDynamic } = config; this.baseUrlMap = baseUrlMap; this.rootPath = rootPath; @@ -593,7 +721,7 @@ Parser.prototype.resolveBaseUrl = function (pageData, config) { reject(error); return; } - const nodes = dom.map((d) => { + const nodes = dom.map(d => { const node = d; const childrenBase = {}; if (this.isDynamic) { @@ -618,7 +746,7 @@ Parser.prototype.resolveBaseUrl = function (pageData, config) { }); }; -Parser.prototype._rebaseReference = function (node, foundBase) { +Parser.prototype._rebaseReference = function(node, foundBase) { const element = node; if (_.isArray(element)) { @@ -630,14 +758,18 @@ Parser.prototype._rebaseReference = function (node, foundBase) { } // Rebase children element const childrenBase = {}; - element.children.forEach((el) => { + element.children.forEach(el => { this._rebaseReference(el, childrenBase); }); // rebase current element if (element.attribs[ATTRIB_INCLUDE_PATH]) { const filePath = element.attribs[ATTRIB_INCLUDE_PATH]; - let newBase = calculateNewBaseUrls(filePath, this.rootPath, this.baseUrlMap); + let newBase = calculateNewBaseUrls( + filePath, + this.rootPath, + this.baseUrlMap, + ); if (newBase) { const { relative, parent } = newBase; // eslint-disable-next-line no-param-reassign @@ -651,17 +783,25 @@ Parser.prototype._rebaseReference = function (node, foundBase) { newBase = combinedBases[bases[0]]; const { children } = element; if (children) { - const currentBase = calculateNewBaseUrls(element.attribs[ATTRIB_CWF], this.rootPath, this.baseUrlMap); + const currentBase = calculateNewBaseUrls( + element.attribs[ATTRIB_CWF], + this.rootPath, + this.baseUrlMap, + ); if (currentBase) { if (currentBase.relative !== newBase) { cheerio.prototype.options.xmlMode = false; const newBaseUrl = `{{hostBaseUrl}}/${newBase}`; - const rendered = nunjucks.renderString(cheerio.html(children), { - // This is to prevent the nunjuck call from converting {{hostBaseUrl}} to an empty string - // and let the hostBaseUrl value be injected later. - hostBaseUrl: '{{hostBaseUrl}}', - baseUrl: newBaseUrl, - }, { path: filePath }); + const rendered = nunjucks.renderString( + cheerio.html(children), + { + // This is to prevent the nunjuck call from converting {{hostBaseUrl}} to an empty string + // and let the hostBaseUrl value be injected later. + hostBaseUrl: '{{hostBaseUrl}}', + baseUrl: newBaseUrl, + }, + { path: filePath }, + ); element.children = cheerio.parseHTML(rendered, true); cheerio.prototype.options.xmlMode = true; } @@ -674,7 +814,11 @@ Parser.prototype._rebaseReference = function (node, foundBase) { return element; }; -Parser.prototype._rebaseReferenceForStaticIncludes = function (pageData, element, config) { +Parser.prototype._rebaseReferenceForStaticIncludes = function( + pageData, + element, + config, +) { if (!config) { return pageData; } @@ -684,20 +828,32 @@ Parser.prototype._rebaseReferenceForStaticIncludes = function (pageData, element } const filePath = element.attribs[ATTRIB_INCLUDE_PATH]; - const fileBase = calculateNewBaseUrls(filePath, config.rootPath, config.baseUrlMap); + const fileBase = calculateNewBaseUrls( + filePath, + config.rootPath, + config.baseUrlMap, + ); if (!fileBase.relative) { return pageData; } const currentPath = element.attribs[ATTRIB_CWF]; - const currentBase = calculateNewBaseUrls(currentPath, config.rootPath, config.baseUrlMap); + const currentBase = calculateNewBaseUrls( + currentPath, + config.rootPath, + config.baseUrlMap, + ); if (currentBase.relative === fileBase.relative) { return pageData; } const newBase = fileBase.relative; const newBaseUrl = `{{hostBaseUrl}}/${newBase}`; - return nunjucks.renderString(pageData, { baseUrl: newBaseUrl }, { path: filePath }); + return nunjucks.renderString( + pageData, + { baseUrl: newBaseUrl }, + { path: filePath }, + ); }; module.exports = Parser; diff --git a/src/lib/markbind/src/utils.js b/src/lib/markbind/src/utils.js index 64f2bc42c9..9297ee173a 100644 --- a/src/lib/markbind/src/utils.js +++ b/src/lib/markbind/src/utils.js @@ -16,7 +16,7 @@ module.exports = { } }, - ensurePosix: (filePath) => { + ensurePosix: filePath => { if (path.sep !== '/') { return filePath.replace(/\\/g, '/'); } diff --git a/src/plugins/algolia.js b/src/plugins/algolia.js index c5a85ff74e..932cf5cc17 100644 --- a/src/plugins/algolia.js +++ b/src/plugins/algolia.js @@ -1,5 +1,7 @@ -const ALGOLIA_CSS_URL = 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css'; -const ALGOLIA_JS_URL = 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js'; +const ALGOLIA_CSS_URL = + 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css'; +const ALGOLIA_JS_URL = + 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js'; const ALGOLIA_INPUT_SELECTOR = '#algolia-search-input'; function buildAlgoliaInitScript(pluginContext) { @@ -18,7 +20,11 @@ function buildAlgoliaInitScript(pluginContext) { } module.exports = { - getLinks: (content, pluginContext, frontMatter, utils) => [utils.buildStylesheet(ALGOLIA_CSS_URL)], - getScripts: (content, pluginContext, frontMatter, utils) => - [utils.buildScript(ALGOLIA_JS_URL), buildAlgoliaInitScript(pluginContext)], + getLinks: (content, pluginContext, frontMatter, utils) => [ + utils.buildStylesheet(ALGOLIA_CSS_URL), + ], + getScripts: (content, pluginContext, frontMatter, utils) => [ + utils.buildScript(ALGOLIA_JS_URL), + buildAlgoliaInitScript(pluginContext), + ], }; diff --git a/src/plugins/filterTags.js b/src/plugins/filterTags.js index d06dfb4b99..2e4fb1d10a 100644 --- a/src/plugins/filterTags.js +++ b/src/plugins/filterTags.js @@ -13,24 +13,30 @@ function filterTags(tags, content) { const $ = cheerio.load(content, { xmlMode: false }); const tagOperations = tags.map(tag => ({ // Trim leading + or -, replace * with .*, add ^ and $ - tagExp: `^${escapeRegExp(tag.replace(/^(\+|-)/g, '')).replace(/\\\*/, '.*')}$`, + tagExp: `^${escapeRegExp(tag.replace(/^(\+|-)/g, '')).replace( + /\\\*/, + '.*', + )}$`, // Whether it is makes tags visible or hides them isHidden: tag.startsWith('-'), })); $('[tags]').each((i, element) => { $(element).attr('hidden', true); - $(element).attr('tags').split(' ').forEach((tag) => { - tagOperations.forEach((tagOperation) => { - if (!tag.match(tagOperation.tagExp)) { - return; - } - if (tagOperation.isHidden) { - $(element).attr('hidden', true); - } else { - $(element).removeAttr('hidden'); - } + $(element) + .attr('tags') + .split(' ') + .forEach(tag => { + tagOperations.forEach(tagOperation => { + if (!tag.match(tagOperation.tagExp)) { + return; + } + if (tagOperation.isHidden) { + $(element).attr('hidden', true); + } else { + $(element).removeAttr('hidden'); + } + }); }); - }); }); $('[hidden]').remove(); return $.html(); @@ -39,7 +45,9 @@ function filterTags(tags, content) { module.exports = { postRender: (content, pluginContext, frontMatter) => { // Tags specified in site.json will be merged with tags specified in front matter - const mergedTags = (frontMatter.tags || []).concat(pluginContext.tags || []); + const mergedTags = (frontMatter.tags || []).concat( + pluginContext.tags || [], + ); return filterTags(mergedTags, content); }, }; diff --git a/src/util/cliUtil.js b/src/util/cliUtil.js index 65e29b737e..f96aaf30ac 100644 --- a/src/util/cliUtil.js +++ b/src/util/cliUtil.js @@ -8,9 +8,14 @@ module.exports = { findRootFolder: (userSpecifiedRoot, siteConfigPath = SITE_CONFIG_NAME) => { if (userSpecifiedRoot) { const resolvedUserSpecifiedRoot = path.resolve(userSpecifiedRoot); - const expectedConfigPath = path.join(resolvedUserSpecifiedRoot, siteConfigPath); + const expectedConfigPath = path.join( + resolvedUserSpecifiedRoot, + siteConfigPath, + ); if (!fs.existsSync(expectedConfigPath)) { - throw new Error(`Config file not found at user specified root ${resolvedUserSpecifiedRoot}`); + throw new Error( + `Config file not found at user specified root ${resolvedUserSpecifiedRoot}`, + ); } return resolvedUserSpecifiedRoot; } @@ -18,9 +23,13 @@ module.exports = { const currentWorkingDir = process.cwd(); // Enforces findUp uses value of process.cwd() to determine starting dir // This allows us to define starting dir when testing by mocking process.cwd() - const foundConfigPath = findUp.sync(siteConfigPath, { cwd: currentWorkingDir }); + const foundConfigPath = findUp.sync(siteConfigPath, { + cwd: currentWorkingDir, + }); if (!foundConfigPath) { - throw new Error(`No config file found in parent directories of ${currentWorkingDir}`); + throw new Error( + `No config file found in parent directories of ${currentWorkingDir}`, + ); } return path.dirname(foundConfigPath); }, diff --git a/src/util/delay.js b/src/util/delay.js index 5b5f733d72..7fa9020059 100644 --- a/src/util/delay.js +++ b/src/util/delay.js @@ -1,20 +1,20 @@ const Promise = require('bluebird'); /** -* Creates a function that delays invoking `func` until after `wait` milliseconds have elapsed -* and the running `func` has resolved/rejected. -* @param func the promise-returning function to delay, -* func should take in a single array -* @param wait the number of milliseconds to delay -* @returns delayedFunc that takes in a single argument (either an array or a single value) -*/ + * Creates a function that delays invoking `func` until after `wait` milliseconds have elapsed + * and the running `func` has resolved/rejected. + * @param func the promise-returning function to delay, + * func should take in a single array + * @param wait the number of milliseconds to delay + * @returns delayedFunc that takes in a single argument (either an array or a single value) + */ module.exports = function delay(func, wait) { let context; let pendingArgs = []; let runningPromise = Promise.resolve(); let waitingPromise = null; - return function (arg) { + return function(arg) { context = this; if (Array.isArray(arg)) { pendingArgs = pendingArgs.concat(arg); @@ -23,14 +23,16 @@ module.exports = function delay(func, wait) { } if (waitingPromise === null) { - waitingPromise = Promise.all([Promise.delay(wait), runningPromise]) - .finally(() => { - runningPromise = waitingPromise || Promise.resolve(); - waitingPromise = null; - const funcPromise = func.apply(context, [pendingArgs]); - pendingArgs = []; - return funcPromise; - }); + waitingPromise = Promise.all([ + Promise.delay(wait), + runningPromise, + ]).finally(() => { + runningPromise = waitingPromise || Promise.resolve(); + waitingPromise = null; + const funcPromise = func.apply(context, [pendingArgs]); + pendingArgs = []; + return funcPromise; + }); } return waitingPromise; diff --git a/src/util/fsUtil.js b/src/util/fsUtil.js index 361b17cd22..2f174d8deb 100644 --- a/src/util/fsUtil.js +++ b/src/util/fsUtil.js @@ -16,16 +16,19 @@ module.exports = { normalizedRoot += path.sep; } const normalizedFilename = path.normalize(fileName); - return (normalizedFilename.substr(0, normalizedRoot.length) === normalizedRoot); + return ( + normalizedFilename.substr(0, normalizedRoot.length) === normalizedRoot + ); }, - isUrl: (unknownPath) => { + isUrl: unknownPath => { const r = new RegExp('^(?:[a-z]+:)?//', 'i'); return r.test(unknownPath); }, - setExtension: (normalizedFilename, ext) => path.join( - path.dirname(normalizedFilename), - path.basename(normalizedFilename, path.extname(normalizedFilename)) + ext, - ), + setExtension: (normalizedFilename, ext) => + path.join( + path.dirname(normalizedFilename), + path.basename(normalizedFilename, path.extname(normalizedFilename)) + ext, + ), }; diff --git a/src/util/logger.js b/src/util/logger.js index dd8b151c79..f01ce481d2 100644 --- a/src/util/logger.js +++ b/src/util/logger.js @@ -8,7 +8,7 @@ const DailyRotateFile = require('winston-daily-rotate-file'); winston.configure({ exitOnError: false, transports: [ - new (winston.transports.Console)({ + new winston.transports.Console({ colorize: true, handleExceptions: true, humanReadableUnhandledException: true, @@ -29,26 +29,29 @@ winston.configure({ }); module.exports = { - error: (text) => { + error: text => { winston.error(text); }, - warn: (text) => { + warn: text => { winston.warn(text); }, - info: (text) => { + info: text => { winston.info(text); }, - verbose: (text) => { + verbose: text => { winston.verbose(text); }, - debug: (text) => { + debug: text => { winston.debug(text); }, - log: (text) => { + log: text => { console.log(text); }, - logo: () => console.log(chalk.cyan(figlet.textSync('MarkBind', { horizontalLayout: 'full' }))), - profile: (key) => { + logo: () => + console.log( + chalk.cyan(figlet.textSync('MarkBind', { horizontalLayout: 'full' })), + ), + profile: key => { winston.profile(key); }, }; diff --git a/test/functional/testUtil/diffPrinter.js b/test/functional/testUtil/diffPrinter.js index e9c1b74ccb..797c744d68 100644 --- a/test/functional/testUtil/diffPrinter.js +++ b/test/functional/testUtil/diffPrinter.js @@ -12,18 +12,18 @@ class DiffPrinter { static printLine(text = '', colour = 'none') { let ansiEscCode = ''; switch (colour) { - case 'red': - ansiEscCode = ANSI_RED; - break; - case 'green': - ansiEscCode = ANSI_GREEN; - break; - case 'grey': - ansiEscCode = ANSI_GREY; - break; - default: - ansiEscCode = ''; - break; + case 'red': + ansiEscCode = ANSI_RED; + break; + case 'green': + ansiEscCode = ANSI_GREEN; + break; + case 'grey': + ansiEscCode = ANSI_GREY; + break; + default: + ansiEscCode = ''; + break; } process.stderr.write(`${ansiEscCode}${text}${ANSI_RESET}\n`); } diff --git a/test/functional/test_site/_markbind/layouts/testAfterSetup/scripts.js b/test/functional/test_site/_markbind/layouts/testAfterSetup/scripts.js index 302e892f17..5bb8b99a89 100644 --- a/test/functional/test_site/_markbind/layouts/testAfterSetup/scripts.js +++ b/test/functional/test_site/_markbind/layouts/testAfterSetup/scripts.js @@ -12,10 +12,13 @@ function addMouseoverSpanListener() { const whiteOnBlue = 'color: white; background-color: blue;'; const originalColor = 'color: #24292e; background-color: #f6f8fa;'; - document.getElementById('mouseover-span').addEventListener('mouseover', () => { - const alertBox = document.getElementById('alert-box'); - alertBox.style.cssText = alertBox.style.cssText === whiteOnBlue ? originalColor : whiteOnBlue; - }); + document + .getElementById('mouseover-span') + .addEventListener('mouseover', () => { + const alertBox = document.getElementById('alert-box'); + alertBox.style.cssText = + alertBox.style.cssText === whiteOnBlue ? originalColor : whiteOnBlue; + }); } /* eslint-disable no-undef */ diff --git a/test/functional/test_site/_markbind/plugins/testMarkbindPlugin.js b/test/functional/test_site/_markbind/plugins/testMarkbindPlugin.js index e696ada3a8..e4d2df9f8e 100644 --- a/test/functional/test_site/_markbind/plugins/testMarkbindPlugin.js +++ b/test/functional/test_site/_markbind/plugins/testMarkbindPlugin.js @@ -2,13 +2,20 @@ const cheerio = module.parent.require('cheerio'); module.exports = { preRender: (content, pluginContext) => - content.replace('Markbind Plugin Pre-render Placeholder', `${pluginContext.pre}`), + content.replace( + 'Markbind Plugin Pre-render Placeholder', + `${pluginContext.pre}`, + ), postRender: (content, pluginContext) => { const $ = cheerio.load(content, { xmlMode: false }); $('#test-markbind-plugin').append(`${pluginContext.post}`); return $.html(); }, - getLinks: (content, pluginContext, frontMatter, utils) => [utils.buildStylesheet('STYLESHEET_LINK')], - getScripts: (content, pluginContext, frontMatter, utils) => - [utils.buildScript('SCRIPT_LINK'), ''], + getLinks: (content, pluginContext, frontMatter, utils) => [ + utils.buildStylesheet('STYLESHEET_LINK'), + ], + getScripts: (content, pluginContext, frontMatter, utils) => [ + utils.buildScript('SCRIPT_LINK'), + '', + ], }; diff --git a/test/functional/test_site/expected/_markbind/plugins/testMarkbindPlugin.js b/test/functional/test_site/expected/_markbind/plugins/testMarkbindPlugin.js index e696ada3a8..e4d2df9f8e 100644 --- a/test/functional/test_site/expected/_markbind/plugins/testMarkbindPlugin.js +++ b/test/functional/test_site/expected/_markbind/plugins/testMarkbindPlugin.js @@ -2,13 +2,20 @@ const cheerio = module.parent.require('cheerio'); module.exports = { preRender: (content, pluginContext) => - content.replace('Markbind Plugin Pre-render Placeholder', `${pluginContext.pre}`), + content.replace( + 'Markbind Plugin Pre-render Placeholder', + `${pluginContext.pre}`, + ), postRender: (content, pluginContext) => { const $ = cheerio.load(content, { xmlMode: false }); $('#test-markbind-plugin').append(`${pluginContext.post}`); return $.html(); }, - getLinks: (content, pluginContext, frontMatter, utils) => [utils.buildStylesheet('STYLESHEET_LINK')], - getScripts: (content, pluginContext, frontMatter, utils) => - [utils.buildScript('SCRIPT_LINK'), ''], + getLinks: (content, pluginContext, frontMatter, utils) => [ + utils.buildStylesheet('STYLESHEET_LINK'), + ], + getScripts: (content, pluginContext, frontMatter, utils) => [ + utils.buildScript('SCRIPT_LINK'), + '', + ], }; diff --git a/test/functional/test_site/expected/markbind/js/setup.js b/test/functional/test_site/expected/markbind/js/setup.js index a58c04b35d..02f9193182 100644 --- a/test/functional/test_site/expected/markbind/js/setup.js +++ b/test/functional/test_site/expected/markbind/js/setup.js @@ -5,7 +5,9 @@ Vue.use(VueStrap); function scrollToUrlAnchorHeading() { if (window.location.hash) { // remove leading hash to get element ID - const headingElement = document.getElementById(window.location.hash.slice(1)); + const headingElement = document.getElementById( + window.location.hash.slice(1), + ); if (headingElement) { headingElement.scrollIntoView(); window.scrollBy(0, -document.body.style.paddingTop.replace('px', '')); @@ -15,37 +17,44 @@ function scrollToUrlAnchorHeading() { function flattenModals() { jQuery('.modal').each((index, modal) => { - jQuery(modal).detach().appendTo(jQuery('#app')); + jQuery(modal) + .detach() + .appendTo(jQuery('#app')); }); } function setupAnchors() { jQuery('h1, h2, h3, h4, h5, h6, .header-wrapper').each((index, heading) => { - jQuery(heading).on('mouseenter', - () => jQuery(heading).find('.fa.fa-anchor').css('visibility', 'visible')); - jQuery(heading).on('mouseleave', - () => jQuery(heading).find('.fa.fa-anchor').css('visibility', 'hidden')); + jQuery(heading).on('mouseenter', () => + jQuery(heading) + .find('.fa.fa-anchor') + .css('visibility', 'visible'), + ); + jQuery(heading).on('mouseleave', () => + jQuery(heading) + .find('.fa.fa-anchor') + .css('visibility', 'hidden'), + ); }); jQuery('.fa-anchor').each((index, anchor) => { - jQuery(anchor).on('click', function () { + jQuery(anchor).on('click', function() { window.location.href = jQuery(this).attr('href'); }); }); } function updateSearchData(vm) { - jQuery.getJSON(`${baseUrl}/siteData.json`) - .then((siteData) => { - // eslint-disable-next-line no-param-reassign - vm.searchData = siteData.pages; - }); + jQuery.getJSON(`${baseUrl}/siteData.json`).then(siteData => { + // eslint-disable-next-line no-param-reassign + vm.searchData = siteData.pages; + }); } const MarkBind = { executeAfterSetupScripts: jQuery.Deferred(), }; -MarkBind.afterSetup = (func) => { +MarkBind.afterSetup = func => { if (document.readyState !== 'loading') { func(); } else { @@ -71,7 +80,7 @@ function setupSiteNav() { // Add event listener for site-nav-btn to toggle itself and site navigation elements. const siteNavBtn = document.getElementById('site-nav-btn'); if (siteNavBtn) { - siteNavBtn.addEventListener('click', function () { + siteNavBtn.addEventListener('click', function() { this.classList.toggle('shift'); document.getElementById('site-nav').classList.toggle('open'); document.getElementById('site-nav-btn-wrap').classList.toggle('open'); @@ -80,19 +89,23 @@ function setupSiteNav() { // Creates event listener for all dropdown-btns in page. Array.prototype.forEach.call( document.getElementsByClassName('dropdown-btn'), - dropdownBtn => dropdownBtn.addEventListener('click', function () { - this.classList.toggle('dropdown-btn-open'); - const dropdownContent = this.nextElementSibling; - const dropdownIcon = this.lastElementChild; - dropdownContent.classList.toggle('dropdown-container-open'); - dropdownIcon.classList.toggle('rotate-icon'); - }), + dropdownBtn => + dropdownBtn.addEventListener('click', function() { + this.classList.toggle('dropdown-btn-open'); + const dropdownContent = this.nextElementSibling; + const dropdownIcon = this.lastElementChild; + dropdownContent.classList.toggle('dropdown-container-open'); + dropdownIcon.classList.toggle('rotate-icon'); + }), ); } function setupPageNav() { jQuery(window).on('activate.bs.scrollspy', (event, obj) => { - document.querySelectorAll(`a[href='${obj.relatedTarget}']`).item(0).scrollIntoView(false); + document + .querySelectorAll(`a[href='${obj.relatedTarget}']`) + .item(0) + .scrollIntoView(false); }); } diff --git a/test/functional/test_site/expected/markbind/layouts/testAfterSetup/scripts.js b/test/functional/test_site/expected/markbind/layouts/testAfterSetup/scripts.js index 302e892f17..5bb8b99a89 100644 --- a/test/functional/test_site/expected/markbind/layouts/testAfterSetup/scripts.js +++ b/test/functional/test_site/expected/markbind/layouts/testAfterSetup/scripts.js @@ -12,10 +12,13 @@ function addMouseoverSpanListener() { const whiteOnBlue = 'color: white; background-color: blue;'; const originalColor = 'color: #24292e; background-color: #f6f8fa;'; - document.getElementById('mouseover-span').addEventListener('mouseover', () => { - const alertBox = document.getElementById('alert-box'); - alertBox.style.cssText = alertBox.style.cssText === whiteOnBlue ? originalColor : whiteOnBlue; - }); + document + .getElementById('mouseover-span') + .addEventListener('mouseover', () => { + const alertBox = document.getElementById('alert-box'); + alertBox.style.cssText = + alertBox.style.cssText === whiteOnBlue ? originalColor : whiteOnBlue; + }); } /* eslint-disable no-undef */ diff --git a/test/functional/test_site/testUtil/diffHtml.js b/test/functional/test_site/testUtil/diffHtml.js index db4fe2dd3f..458d6b615b 100644 --- a/test/functional/test_site/testUtil/diffHtml.js +++ b/test/functional/test_site/testUtil/diffHtml.js @@ -6,10 +6,13 @@ const jsdiff = require('diff'); * false: src="" * src="..." */ -const endsWithUnclosedPath = (fragment) => { +const endsWithUnclosedPath = fragment => { for (let i = fragment.length - 1; i > 4; i -= 1) { if (fragment[i] === '"') { - if (fragment.substring(i - 4, i) === 'src=' || fragment.substring(i - 5, i) === 'href=') { + if ( + fragment.substring(i - 4, i) === 'src=' || + fragment.substring(i - 5, i) === 'href=' + ) { return true; } return false; @@ -26,7 +29,7 @@ const endsWithUnclosedPath = (fragment) => { *
    * src="... */ -const endsWithOpeningTag = (fragment) => { +const endsWithOpeningTag = fragment => { let numUnmatchedClosingBracket = 0; for (let i = fragment.length - 1; i >= 0; i -= 1) { if (fragment[i] === '>') { @@ -50,7 +53,7 @@ const endsWithOpeningTag = (fragment) => { * false: < src="... * > "... */ -const startsWithClosedPath = (fragment) => { +const startsWithClosedPath = fragment => { for (let i = 0; i <= fragment.length - 1; i += 1) { if (fragment[i] === '<' || fragment[i] === '>') { return false; @@ -80,11 +83,9 @@ const diffHtml = (expected, actual) => { const isDiff = part => part.added || part.removed; // assumes no space between paths - const isClosedPath = fragment => - insidePath - && startsWithClosedPath(fragment); + const isClosedPath = fragment => insidePath && startsWithClosedPath(fragment); - diff.forEach((part) => { + diff.forEach(part => { if (isClosedPath(part.value)) { insidePath = false; } diff --git a/test/unit/Site.test.js b/test/unit/Site.test.js index 56367760f0..ade9495f09 100644 --- a/test/unit/Site.test.js +++ b/test/unit/Site.test.js @@ -59,30 +59,70 @@ test('Site Generate builds the correct amount of assets', async () => { expect(fs.existsSync(path.resolve('inner/_site'))).toEqual(true); // siteData - expect(fs.existsSync(path.resolve('inner/_site/siteData.json'))).toEqual(true); + expect(fs.existsSync(path.resolve('inner/_site/siteData.json'))).toEqual( + true, + ); // markbind expect(fs.existsSync(path.resolve('inner/_site/markbind'))).toEqual(true); // css - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/bootstrap.min.css'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/bootstrap.min.css.map'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/github.min.css'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/markbind.css'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/page-nav.css'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/css/site-nav.css'))).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/css/bootstrap.min.css')), + ).toEqual(true); + expect( + fs.existsSync( + path.resolve('inner/_site/markbind/css/bootstrap.min.css.map'), + ), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/css/github.min.css')), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/css/markbind.css')), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/css/page-nav.css')), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/css/site-nav.css')), + ).toEqual(true); // js - expect(fs.existsSync(path.resolve('inner/_site/markbind/js/setup.js'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/js/vue.min.js'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/js/vue-strap.min.js'))).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/js/setup.js')), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/js/vue.min.js')), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/js/vue-strap.min.js')), + ).toEqual(true); // layouts - expect(fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/footer.md'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/head.md'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/navigation.md'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/scripts.js'))).toEqual(true); - expect(fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/styles.css'))).toEqual(true); + expect( + fs.existsSync( + path.resolve('inner/_site/markbind/layouts/default/footer.md'), + ), + ).toEqual(true); + expect( + fs.existsSync(path.resolve('inner/_site/markbind/layouts/default/head.md')), + ).toEqual(true); + expect( + fs.existsSync( + path.resolve('inner/_site/markbind/layouts/default/navigation.md'), + ), + ).toEqual(true); + expect( + fs.existsSync( + path.resolve('inner/_site/markbind/layouts/default/scripts.js'), + ), + ).toEqual(true); + expect( + fs.existsSync( + path.resolve('inner/_site/markbind/layouts/default/styles.css'), + ), + ).toEqual(true); }); test('Site Init in existing directory generates correct assets', async () => { @@ -101,32 +141,53 @@ test('Site Init in existing directory generates correct assets', async () => { expect(fs.existsSync(path.resolve('_markbind/boilerplates'))).toEqual(true); // footer.md - expect(fs.readFileSync(path.resolve('_markbind/footers/footer.md'), 'utf8')).toEqual(FOOTER_MD_DEFAULT); + expect( + fs.readFileSync(path.resolve('_markbind/footers/footer.md'), 'utf8'), + ).toEqual(FOOTER_MD_DEFAULT); // head folder expect(fs.existsSync(path.resolve('_markbind/head'), 'utf8')).toEqual(true); // site-nav.md - expect(fs.readFileSync(path.resolve('_markbind/navigation/site-nav.md'), 'utf8')) - .toEqual(SITE_NAV_MD_DEFAULT); + expect( + fs.readFileSync(path.resolve('_markbind/navigation/site-nav.md'), 'utf8'), + ).toEqual(SITE_NAV_MD_DEFAULT); // user defined variables - expect(fs.readFileSync(path.resolve('_markbind/variables.md'), 'utf8')).toEqual(USER_VARIABLES_DEFAULT); + expect( + fs.readFileSync(path.resolve('_markbind/variables.md'), 'utf8'), + ).toEqual(USER_VARIABLES_DEFAULT); // site.json - expect(fs.readJsonSync(path.resolve('site.json'))).toEqual(JSON.parse(SITE_JSON_DEFAULT)); + expect(fs.readJsonSync(path.resolve('site.json'))).toEqual( + JSON.parse(SITE_JSON_DEFAULT), + ); // index.md - expect(fs.readFileSync(path.resolve('index.md'), 'utf8')).toEqual(INDEX_MD_DEFAULT); + expect(fs.readFileSync(path.resolve('index.md'), 'utf8')).toEqual( + INDEX_MD_DEFAULT, + ); // layout defaults LAYOUT_FILES_DEFAULT.forEach(layoutFile => - expect(fs.readFileSync(path.resolve(`_markbind/layouts/default/${layoutFile}`), 'utf8')).toEqual('')); - expect(fs.readFileSync(path.resolve('_markbind/layouts/default/scripts.js'), 'utf8')) - .toEqual(LAYOUT_SCRIPTS_DEFAULT); + expect( + fs.readFileSync( + path.resolve(`_markbind/layouts/default/${layoutFile}`), + 'utf8', + ), + ).toEqual(''), + ); + expect( + fs.readFileSync( + path.resolve('_markbind/layouts/default/scripts.js'), + 'utf8', + ), + ).toEqual(LAYOUT_SCRIPTS_DEFAULT); // plugins folder - expect(fs.existsSync(path.resolve('_markbind/plugins'), 'utf8')).toEqual(true); + expect(fs.existsSync(path.resolve('_markbind/plugins'), 'utf8')).toEqual( + true, + ); }); test('Site Init in directory which does not exist generates correct assets', async () => { @@ -142,38 +203,63 @@ test('Site Init in directory which does not exist generates correct assets', asy expect(paths.length).toEqual(originalNumFiles + expectedNumBuilt); - expect(fs.existsSync(path.resolve('newDir/_markbind/boilerplates'))).toEqual(true); + expect(fs.existsSync(path.resolve('newDir/_markbind/boilerplates'))).toEqual( + true, + ); // footer.md - expect(fs.readFileSync(path.resolve('newDir/_markbind/footers/footer.md'), 'utf8')) - .toEqual(FOOTER_MD_DEFAULT); + expect( + fs.readFileSync(path.resolve('newDir/_markbind/footers/footer.md'), 'utf8'), + ).toEqual(FOOTER_MD_DEFAULT); // head folder - expect(fs.existsSync(path.resolve('newDir/_markbind/head'), 'utf8')).toEqual(true); + expect(fs.existsSync(path.resolve('newDir/_markbind/head'), 'utf8')).toEqual( + true, + ); // site-nav.md - expect(fs.readFileSync(path.resolve('newDir/_markbind/navigation/site-nav.md'), 'utf8')) - .toEqual(SITE_NAV_MD_DEFAULT); + expect( + fs.readFileSync( + path.resolve('newDir/_markbind/navigation/site-nav.md'), + 'utf8', + ), + ).toEqual(SITE_NAV_MD_DEFAULT); // user defined variables - expect(fs.readFileSync(path.resolve('newDir/_markbind/variables.md'), 'utf8')) - .toEqual(USER_VARIABLES_DEFAULT); + expect( + fs.readFileSync(path.resolve('newDir/_markbind/variables.md'), 'utf8'), + ).toEqual(USER_VARIABLES_DEFAULT); // site.json - expect(fs.readJsonSync(path.resolve('newDir/site.json'))).toEqual(JSON.parse(SITE_JSON_DEFAULT)); + expect(fs.readJsonSync(path.resolve('newDir/site.json'))).toEqual( + JSON.parse(SITE_JSON_DEFAULT), + ); // index.md - expect(fs.readFileSync(path.resolve('newDir/index.md'), 'utf8')).toEqual(INDEX_MD_DEFAULT); + expect(fs.readFileSync(path.resolve('newDir/index.md'), 'utf8')).toEqual( + INDEX_MD_DEFAULT, + ); // layout defaults LAYOUT_FILES_DEFAULT.forEach(layoutFile => - expect(fs.readFileSync(path.resolve(`newDir/_markbind/layouts/default/${layoutFile}`), 'utf8')) - .toEqual('')); - expect(fs.readFileSync(path.resolve('newDir/_markbind/layouts/default/scripts.js'), 'utf8')) - .toEqual(LAYOUT_SCRIPTS_DEFAULT); + expect( + fs.readFileSync( + path.resolve(`newDir/_markbind/layouts/default/${layoutFile}`), + 'utf8', + ), + ).toEqual(''), + ); + expect( + fs.readFileSync( + path.resolve('newDir/_markbind/layouts/default/scripts.js'), + 'utf8', + ), + ).toEqual(LAYOUT_SCRIPTS_DEFAULT); // plugins folder - expect(fs.existsSync(path.resolve('newDir/_markbind/plugins'), 'utf8')).toEqual(true); + expect( + fs.existsSync(path.resolve('newDir/_markbind/plugins'), 'utf8'), + ).toEqual(true); }); test('Site baseurls are correct for sub nested subsites', async () => { @@ -220,7 +306,10 @@ test('Site read site config for default', async () => { fs.vol.fromJSON(json, ''); const siteConfigDefaults = { enableSearch: true }; - const expectedSiteConfig = { ...JSON.parse(SITE_JSON_DEFAULT), ...siteConfigDefaults }; + const expectedSiteConfig = { + ...JSON.parse(SITE_JSON_DEFAULT), + ...siteConfigDefaults, + }; const site = new Site('./', '_site'); await site.readSiteConfig(); expect(site.siteConfig).toEqual(expectedSiteConfig); @@ -235,11 +324,7 @@ test('Site read site config for custom site config', async () => { title: 'My Markbind Website', }, ], - ignore: [ - '_site/*', - '*.json', - '*.md', - ], + ignore: ['_site/*', '*.json', '*.md'], deploy: { message: 'Site Update.', }, @@ -263,10 +348,10 @@ test('Site resolves variables referencing other variables', async () => { 'src/template/page.ejs': PAGE_EJS, 'site.json': SITE_JSON_DEFAULT, '_markbind/variables.md': - 'variable' - + '{{level1}}' - + 'Blue text' - + '{{level3}}', + 'variable' + + '{{level1}}' + + 'Blue text' + + '{{level3}}', }; fs.vol.fromJSON(json, ''); @@ -298,11 +383,11 @@ test('Site read correct user defined variables', async () => { 'sub/sub/site.json': SITE_JSON_DEFAULT, 'otherSub/sub/site.json': SITE_JSON_DEFAULT, '_markbind/variables.md': - 'variable' - + '2', + 'variable2', 'sub/_markbind/variables.md': 'sub_variable', 'sub/sub/_markbind/variables.md': '9999', - 'otherSub/sub/_markbind/variables.md': 'other_variable', + 'otherSub/sub/_markbind/variables.md': + 'other_variable', }; fs.vol.fromJSON(json, ''); @@ -342,8 +427,11 @@ test('Site deploys with default settings', async () => { const site = new Site('./', '_site'); await site.deploy(); expect(ghpages.dir).toEqual('_site'); - expect(ghpages.options) - .toEqual({ branch: 'gh-pages', message: 'Site Update.', repo: '' }); + expect(ghpages.options).toEqual({ + branch: 'gh-pages', + message: 'Site Update.', + repo: '', + }); }); test('Site deploys with custom settings', async () => { @@ -362,8 +450,11 @@ test('Site deploys with custom settings', async () => { const site = new Site('./', '_site'); await site.deploy(); expect(ghpages.dir).toEqual('_site'); - expect(ghpages.options) - .toEqual({ branch: 'master', message: 'Custom Site Update.', repo: 'https://github.com/USER/REPO.git' }); + expect(ghpages.options).toEqual({ + branch: 'master', + message: 'Custom Site Update.', + repo: 'https://github.com/USER/REPO.git', + }); }); test('Site should not deploy without a built site', async () => { @@ -373,11 +464,12 @@ test('Site should not deploy without a built site', async () => { }; fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); - await expect(site.deploy()) - .rejects - .toThrow( - new Error('The site directory does not exist. ' - + 'Please build the site first before deploy.')); + await expect(site.deploy()).rejects.toThrow( + new Error( + 'The site directory does not exist. ' + + 'Please build the site first before deploy.', + ), + ); }); describe('Site deploy with Travis', () => { @@ -409,9 +501,15 @@ describe('Site deploy with Travis', () => { fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); await site.deploy(true); - expect(ghpages.options.repo) - .toEqual(`https://${process.env.GITHUB_TOKEN}@github.com/${process.env.TRAVIS_REPO_SLUG}.git`); - expect(ghpages.options.user).toEqual({ name: 'Deployment Bot', email: 'deploy@travis-ci.org' }); + expect(ghpages.options.repo).toEqual( + `https://${process.env.GITHUB_TOKEN}@github.com/${ + process.env.TRAVIS_REPO_SLUG + }.git`, + ); + expect(ghpages.options.user).toEqual({ + name: 'Deployment Bot', + email: 'deploy@travis-ci.org', + }); }); test('Site deploy -t/--travis deploys with custom GitHub repo', async () => { @@ -429,8 +527,9 @@ describe('Site deploy with Travis', () => { fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); await site.deploy(true); - expect(ghpages.options.repo) - .toEqual(`https://${process.env.GITHUB_TOKEN}@github.com/USER/REPO.git`); + expect(ghpages.options.repo).toEqual( + `https://${process.env.GITHUB_TOKEN}@github.com/USER/REPO.git`, + ); }); test('Site deploy -t/--travis deploys to correct repo when .git is in repo name', async () => { @@ -446,8 +545,11 @@ describe('Site deploy with Travis', () => { fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); await site.deploy(true); - expect(ghpages.options.repo) - .toEqual(`https://${process.env.GITHUB_TOKEN}@github.com/TRAVIS_USER/TRAVIS_REPO.github.io.git`); + expect(ghpages.options.repo).toEqual( + `https://${ + process.env.GITHUB_TOKEN + }@github.com/TRAVIS_USER/TRAVIS_REPO.github.io.git`, + ); }); test('Site deploy -t/--travis should not deploy if not in Travis', async () => { @@ -458,9 +560,9 @@ describe('Site deploy with Travis', () => { }; fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); - await expect(site.deploy(true)) - .rejects - .toThrow(new Error('-t/--travis should only be run in Travis CI.')); + await expect(site.deploy(true)).rejects.toThrow( + new Error('-t/--travis should only be run in Travis CI.'), + ); }); test('Site deploy -t/--travis should not deploy without authentication token', async () => { @@ -473,9 +575,9 @@ describe('Site deploy with Travis', () => { }; fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); - await expect(site.deploy(true)) - .rejects - .toThrow(new Error('The environment variable GITHUB_TOKEN does not exist.')); + await expect(site.deploy(true)).rejects.toThrow( + new Error('The environment variable GITHUB_TOKEN does not exist.'), + ); }); test('Site deploy -t/--travis should not deploy if custom repository is not on GitHub', async () => { @@ -491,10 +593,14 @@ describe('Site deploy with Travis', () => { }; fs.vol.fromJSON(json, ''); const site = new Site('./', '_site'); - await expect(site.deploy(true)) - .rejects - .toThrow(new Error('-t/--travis expects a GitHub repository.\n' - + `The specified repository ${invalidRepoConfig.deploy.repo} is not valid.`)); + await expect(site.deploy(true)).rejects.toThrow( + new Error( + '-t/--travis expects a GitHub repository.\n' + + `The specified repository ${ + invalidRepoConfig.deploy.repo + } is not valid.`, + ), + ); }); }); @@ -588,16 +694,12 @@ const siteJsonResolvePropertiesTestCases = [ }, ]; -siteJsonResolvePropertiesTestCases.forEach((testCase) => { +siteJsonResolvePropertiesTestCases.forEach(testCase => { test(testCase.name, async () => { const customSiteConfig = { baseUrl: '', pages: testCase.pages, - ignore: [ - '_site/*', - '*.json', - '*.md', - ], + ignore: ['_site/*', '*.json', '*.md'], deploy: { message: 'Site Update.', }, @@ -611,8 +713,7 @@ siteJsonResolvePropertiesTestCases.forEach((testCase) => { const site = new Site('./', '_site'); site.siteConfig = customSiteConfig; await site.collectAddressablePages(); - expect(site.addressablePages) - .toEqual(testCase.expected); + expect(site.addressablePages).toEqual(testCase.expected); }); }); @@ -629,11 +730,7 @@ test('Site config throws error on duplicate page src', async () => { title: 'Title', }, ], - ignore: [ - '_site/*', - '*.json', - '*.md', - ], + ignore: ['_site/*', '*.json', '*.md'], deploy: { message: 'Site Update.', }, @@ -646,7 +743,7 @@ test('Site config throws error on duplicate page src', async () => { const site = new Site('./', '_site'); site.siteConfig = customSiteConfig; - expect(site.collectAddressablePages()) - .rejects - .toThrow(new Error('Duplicate page entries found in site config: index.md')); + expect(site.collectAddressablePages()).rejects.toThrow( + new Error('Duplicate page entries found in site config: index.md'), + ); }); diff --git a/test/unit/cliUtil.test.js b/test/unit/cliUtil.test.js index 31d1ad58e8..6f3499ab78 100644 --- a/test/unit/cliUtil.test.js +++ b/test/unit/cliUtil.test.js @@ -18,16 +18,18 @@ test('findRootFolder returns user specified root if site config is found there', }; fs.vol.fromJSON(json, ''); const resolvedUserSpecificRoot = path.resolve('userSpecifiedRoot'); - expect(cliUtil.findRootFolder('userSpecifiedRoot')).toBe(resolvedUserSpecificRoot); + expect(cliUtil.findRootFolder('userSpecifiedRoot')).toBe( + resolvedUserSpecificRoot, + ); }); test('findRootFolder throws error if site config is not found in user specified root', () => { const resolvedUserSpecificRoot = path.resolve('userSpecifiedRoot'); - expect( - () => { - cliUtil.findRootFolder('userSpecifiedRoot'); - }) - .toThrow(`Config file not found at user specified root ${resolvedUserSpecificRoot}`); + expect(() => { + cliUtil.findRootFolder('userSpecifiedRoot'); + }).toThrow( + `Config file not found at user specified root ${resolvedUserSpecificRoot}`, + ); }); test('findRootFolder without user specified root returns first parent dir containing site config', () => { @@ -50,10 +52,7 @@ test('findRootFolder without user specified root throws error if no parent dirs const nestedDir = path.join(currentWorkingDir, 'nested'); fs.vol.fromJSON(json, currentWorkingDir); process.cwd = jest.fn().mockReturnValue(nestedDir); - expect( - () => { - cliUtil.findRootFolder(); - }) - .toThrow(`No config file found in parent directories of ${nestedDir}`); + expect(() => { + cliUtil.findRootFolder(); + }).toThrow(`No config file found in parent directories of ${nestedDir}`); }); - diff --git a/test/unit/parser.test.js b/test/unit/parser.test.js index e02458be19..b0b6bdf13d 100644 --- a/test/unit/parser.test.js +++ b/test/unit/parser.test.js @@ -18,15 +18,10 @@ test('includeFile replaces with
    ', async () => { const indexPath = path.resolve('index.md'); const includePath = path.resolve('include.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join('\n'); const include = ['# Include'].join('\n'); - const json = { 'index.md': index, 'include.md': include, @@ -59,11 +54,9 @@ test('includeFile replaces with
    ', async const indexPath = path.resolve('index.md'); const existPath = path.resolve('exist.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join( + '\n', + ); const exist = ['# Exist'].join('\n'); @@ -119,11 +112,7 @@ test('includeFile replaces with empty < userDefinedVariablesMap: DEFAULT_USER_DEFINED_VARIABLES_MAP, }); - const expected = [ - '# Index', - '
    ', - '', - ].join('\n'); + const expected = ['# Index', '
    ', ''].join('\n'); expect(result).toEqual(expected); }); @@ -132,16 +121,13 @@ test('includeFile replaces with
    ', async const indexPath = path.resolve('index.md'); const includePath = path.resolve('include.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join( + '\n', + ); - const include = [ - '# Include', - 'existing segment', - ].join('\n'); + const include = ['# Include', 'existing segment'].join( + '\n', + ); const json = { 'index.md': index, @@ -183,8 +169,9 @@ test('includeFile replaces with error with error { + errorHandler: e => { expect(e.message).toEqual(expectedErrorMessage); }, }); @@ -225,10 +212,9 @@ test('includeFile replaces with
    '', ].join('\n'); - const include = [ - '# Include', - 'existing segment', - ].join('\n'); + const include = ['# Include', 'existing segment'].join( + '\n', + ); const json = { 'index.md': index, @@ -302,17 +288,9 @@ test('includeFile detects cyclic references for static cyclic includes', async ( const indexPath = path.resolve('index.md'); const includePath = path.resolve('include.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join('\n'); - const include = [ - '# Include', - '', - '', - ].join('\n'); + const include = ['# Include', '', ''].join('\n'); const json = { 'index.md': index, @@ -334,7 +312,7 @@ test('includeFile detects cyclic references for static cyclic includes', async ( ].join('\n'); const markbinder = new MarkBind({ - errorHandler: (e) => { + errorHandler: e => { expect(e.message).toEqual(expectedErrorMessage); }, }); @@ -353,17 +331,13 @@ test('includeFile processes successfully for dynamic cyclic includes', async () const indexPath = path.resolve('index.md'); const includePath = path.resolve('include.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join( + '\n', + ); - const include = [ - '# Include', - '', - '', - ].join('\n'); + const include = ['# Include', '', ''].join( + '\n', + ); const json = { 'index.md': index, @@ -383,8 +357,8 @@ test('includeFile processes successfully for dynamic cyclic includes', async () const expected = [ '# Index', - `', + `', '', ].join('\n'); @@ -396,15 +370,12 @@ test('includeFile replaces with ', async () => { const indexPath = path.resolve('index.md'); const includePath = path.resolve('include.md'); - const index = [ - '# Index', - '', - '', - ].join('\n'); + const index = ['# Index', '', ''].join( + '\n', + ); const include = ['# Include'].join('\n'); - const json = { 'index.md': index, 'include.md': include, @@ -423,8 +394,8 @@ test('includeFile replaces with ', async () => { const expected = [ '# Index', - `', + `', '', ].join('\n'); @@ -452,10 +423,7 @@ test('renderFile converts markdown headers to

    ', async () => { rootPath, }); - const expected = [ - '

    Index

    ', - '', - ].join('\n'); + const expected = ['

    Index

    ', ''].join('\n'); expect(result).toEqual(expected); }); diff --git a/test/unit/utils/data.js b/test/unit/utils/data.js index 54f4da70e0..0a242a7248 100644 --- a/test/unit/utils/data.js +++ b/test/unit/utils/data.js @@ -5,97 +5,104 @@ module.exports.LAYOUT_FILES_DEFAULT = [ 'styles.css', ]; -module.exports.LAYOUT_SCRIPTS_DEFAULT = 'MarkBind.afterSetup(() => {\n' -+ ' // Include code to be called after MarkBind setup here.\n' -+ '});\n'; +module.exports.LAYOUT_SCRIPTS_DEFAULT = + 'MarkBind.afterSetup(() => {\n' + + ' // Include code to be called after MarkBind setup here.\n' + + '});\n'; -module.exports.PAGE_EJS = '\n' - + '\n' - + '\n' - + ' <%- headFileTopContent %>\n' - + ' \n' - + ' \n' - + ' \n' - + ' <%= title %>\n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' <% if (siteNav) { %><% } %>\n' - + ' <%- headFileBottomContent %>\n' - + ' <% if (faviconUrl) { %><% } %>\n' - + '\n' - + '\n' - + '
    \n' - + ' <%- content %>\n' - + '
    \n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n'; +module.exports.PAGE_EJS = + '\n' + + '\n' + + '\n' + + ' <%- headFileTopContent %>\n' + + ' \n' + + ' \n' + + ' \n' + + ' <%= title %>\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' <% if (siteNav) { %><% } %>\n' + + ' <%- headFileBottomContent %>\n' + + ' <% if (faviconUrl) { %><% } %>\n' + + '\n' + + '\n' + + '
    \n' + + ' <%- content %>\n' + + '
    \n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n'; -module.exports.SITE_JSON_DEFAULT = '{\n' - + ' "baseUrl": "",\n' - + ' "titlePrefix": "",\n' - + ' "ignore": [\n' - + ' "_markbind/layouts/*",\n' - + ' "_markbind/logs/*",\n' - + ' "_site/*",\n' - + ' "site.json",\n' - + ' "*.md",\n' - + ' "*.mbd",\n' - + ' ".git/*"\n' - + ' ],\n' - + ' "pages": [\n' - + ' {\n' - + ' "src": "index.md",\n' - + ' "title": "Hello World"\n' - + ' },\n' - + ' {\n' - + ' "glob" : "**/index.md"\n' - + ' },\n' - + ' {\n' - + ' "glob" : "**/*.+(md|mbd)"\n' - + ' }\n' - + ' ],\n' - + ' "deploy": {\n' - + ' "message": "Site Update."\n' - + ' }\n' - + '}\n'; +module.exports.SITE_JSON_DEFAULT = + '{\n' + + ' "baseUrl": "",\n' + + ' "titlePrefix": "",\n' + + ' "ignore": [\n' + + ' "_markbind/layouts/*",\n' + + ' "_markbind/logs/*",\n' + + ' "_site/*",\n' + + ' "site.json",\n' + + ' "*.md",\n' + + ' "*.mbd",\n' + + ' ".git/*"\n' + + ' ],\n' + + ' "pages": [\n' + + ' {\n' + + ' "src": "index.md",\n' + + ' "title": "Hello World"\n' + + ' },\n' + + ' {\n' + + ' "glob" : "**/index.md"\n' + + ' },\n' + + ' {\n' + + ' "glob" : "**/*.+(md|mbd)"\n' + + ' }\n' + + ' ],\n' + + ' "deploy": {\n' + + ' "message": "Site Update."\n' + + ' }\n' + + '}\n'; -module.exports.FOOTER_MD_DEFAULT = '
    \n' - + '
    \n' - + ' This is a dynamic height footer that supports markdown :smile:!\n' - + '
    \n' - + ' \n' - + '
    \n' - + ' [Generated by {{MarkBind}} on {{timestamp}}]\n' - + '
    \n' - + '
    \n'; +module.exports.FOOTER_MD_DEFAULT = + '
    \n' + + '
    \n' + + ' This is a dynamic height footer that supports markdown :smile:!\n' + + '
    \n' + + ' \n' + + '
    \n' + + ' [Generated by {{MarkBind}} on {{timestamp}}]\n' + + '
    \n' + + '
    \n'; -module.exports.INDEX_MD_DEFAULT = '\n' - + ' title: "Hello World"\n' - + ' footer: footer.md\n' - + ' siteNav: site-nav.md\n' - + '\n\n' - + '# Hello world\n' - + 'Welcome to your page generated with MarkBind.\n'; +module.exports.INDEX_MD_DEFAULT = + '\n' + + ' title: "Hello World"\n' + + ' footer: footer.md\n' + + ' siteNav: site-nav.md\n' + + '\n\n' + + '# Hello world\n' + + 'Welcome to your page generated with MarkBind.\n'; -module.exports.SITE_NAV_MD_DEFAULT = '\n' - + '* [Home :glyphicon-home:]({{baseUrl}}/index.html)\n' - + '\n'; +module.exports.SITE_NAV_MD_DEFAULT = + '\n' + + '* [Home :glyphicon-home:]({{baseUrl}}/index.html)\n' + + '\n'; -module.exports.USER_VARIABLES_DEFAULT = '\n' - + 'To inject this HTML segment in your markbind files, use {{ example }} where you want to place it.\n' - + 'More generally, surround the segment\'s id with double curly braces.\n' - + ''; +module.exports.USER_VARIABLES_DEFAULT = + '\n' + + 'To inject this HTML segment in your markbind files, use {{ example }} where you want to place it.\n' + + "More generally, surround the segment's id with double curly braces.\n" + + ''; From d247f6c0b9ae34523fc511ce12aa19aecd403f55 Mon Sep 17 00:00:00 2001 From: Marvin Chin Date: Thu, 7 Mar 2019 23:29:52 +0800 Subject: [PATCH 3/3] Add package-lock.json --- package-lock.json | 237 +++++++++++++++++++++++++++------------------- 1 file changed, 141 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7267315389..da76aee57c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "@sindresorhus/slugify": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-0.8.0.tgz", - "integrity": "sha512-Y+C3aG0JHmi4nCfixHgq0iAtqWCjMCliWghf6fXbemRKSGzpcrHdYxGZGDt8MeFg+gH7ounfMbz6WogqKCWvDg==", + "integrity": "sha1-VVC3+gZPOoqCZRRjrWNTeAVMctA=", "requires": { "escape-string-regexp": "1.0.5", "lodash.deburr": "4.1.0" @@ -291,7 +291,7 @@ "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", "dev": true }, "async": { @@ -310,7 +310,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", "dev": true }, "asynckit": { @@ -395,7 +395,7 @@ "babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", "dev": true, "requires": { "babel-messages": "6.23.0", @@ -499,7 +499,7 @@ "source-map-support": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", "dev": true, "requires": { "source-map": "0.5.7" @@ -559,7 +559,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", "dev": true }, "ms": { @@ -585,7 +585,7 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", "dev": true }, "balanced-match": { @@ -596,7 +596,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "1.0.1", @@ -739,7 +739,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "1.0.0", @@ -824,7 +824,7 @@ "css-select": "1.2.0", "dom-serializer": "0.1.0", "entities": "1.1.1", - "htmlparser2": "github:MarkBind/htmlparser2#815b507c5268a178fa24741d6f74fcc0bc9be4cd", + "htmlparser2": "^3.9.1", "lodash.assignin": "4.2.0", "lodash.bind": "4.2.1", "lodash.defaults": "4.2.0", @@ -864,13 +864,13 @@ "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=", "dev": true }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { "arr-union": "3.1.0", @@ -1271,7 +1271,7 @@ "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { "is-descriptor": "1.0.2", @@ -1351,13 +1351,13 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", "dev": true }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", "dev": true, "requires": { "esutils": "2.0.2" @@ -1387,7 +1387,7 @@ "domexception": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "integrity": "sha1-k3RCZEymoxJh7zbj7Gd/6AVYLJA=", "dev": true, "requires": { "webidl-conversions": "4.0.2" @@ -1641,16 +1641,25 @@ "eslint-config-airbnb-base": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", - "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "integrity": "sha1-OGRB5UoSzNlXsKklZKS6/r10eUQ=", "dev": true, "requires": { "eslint-restricted-globals": "0.1.1" } }, + "eslint-config-prettier": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.1.0.tgz", + "integrity": "sha512-zILwX9/Ocz4SV2vX7ox85AsrAgXV3f2o2gpIicdMIOra48WYqgUnWNH/cR/iHtmD2Vb3dLSC3LiEJnS05Gkw7w==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", "dev": true, "requires": { "debug": "2.6.9", @@ -1755,6 +1764,15 @@ "lodash": "4.17.5" } }, + "eslint-plugin-prettier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz", + "integrity": "sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-restricted-globals": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", @@ -1774,7 +1792,7 @@ "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", "dev": true }, "espree": { @@ -1891,7 +1909,7 @@ "expect": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.3.tgz", - "integrity": "sha512-XcNXEPehqn8b/jm8FYotdX0YrXn36qp4HWlrVT4ktwQas1l1LPxiVWncYnnL2eyMtKAmVIaG0XAp0QlrqJaxaA==", + "integrity": "sha1-1aKdCg4fshU1V8rvJnTUVH6RRnQ=", "dev": true, "requires": { "ansi-styles": "3.2.1", @@ -1905,7 +1923,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -1932,7 +1950,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "2.0.4" @@ -1976,6 +1994,12 @@ "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-extend": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/fast-extend/-/fast-extend-0.0.2.tgz", @@ -1997,7 +2021,7 @@ "fast-safe-stringify": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", - "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + "integrity": "sha1-BLJhBsxWaB9RoETPwNds8ACKwsI=" }, "fastmatter": { "version": "2.0.1", @@ -2049,7 +2073,7 @@ "fecha": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + "integrity": "sha1-lI50FX3xoy/RsSw6PDzctuydls0=" }, "figlet": { "version": "1.2.0", @@ -2078,9 +2102,9 @@ "file-stream-rotator": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.4.1.tgz", - "integrity": "sha512-W3aa3QJEc8BS2MmdVpQiYLKHj3ijpto1gMDlsgCRSKfIUe6MwkcpODGPQ3vZfb0XvCeCqlu9CBQTN7oQri2TZQ==", + "integrity": "sha1-CfZ7htbqWJ0gt4UsUcWd5V2RbW0=", "requires": { - "moment": "2.22.1" + "moment": "^2.11.2" } }, "filename-regex": { @@ -2318,7 +2342,6 @@ "boom": { "version": "2.10.1", "bundled": true, - "optional": true, "requires": { "hoek": "2.16.3" } @@ -3018,7 +3041,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, "functional-red-black-tree": { @@ -3033,6 +3056,12 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -3325,7 +3354,7 @@ "html-encoding-sniffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "integrity": "sha1-5w2EuU2lOqN14R/jo1G+ZkLKRvg=", "dev": true, "requires": { "whatwg-encoding": "1.0.3" @@ -3333,6 +3362,7 @@ }, "htmlparser2": { "version": "github:MarkBind/htmlparser2#815b507c5268a178fa24741d6f74fcc0bc9be4cd", + "from": "github:MarkBind/htmlparser2#v3.10.0-markbind.1", "requires": { "domelementtype": "1.3.0", "domhandler": "2.4.1", @@ -3389,7 +3419,7 @@ "import-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "integrity": "sha1-Xk/9wD9P5sAJxnKb6yljHC+CJ7w=", "dev": true, "requires": { "pkg-dir": "2.0.0", @@ -3444,7 +3474,7 @@ "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", "dev": true, "requires": { "ansi-escapes": "3.0.0", @@ -3498,7 +3528,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -3528,7 +3558,7 @@ "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "dev": true, "requires": { "loose-envify": "1.3.1" @@ -3747,7 +3777,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "3.0.1" @@ -3819,7 +3849,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", "dev": true }, "is-wsl": { @@ -4173,7 +4203,7 @@ "jest-changed-files": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.4.3.tgz", - "integrity": "sha512-83Dh0w1aSkUNFhy5d2dvqWxi/y6weDwVVLU6vmK0cV9VpRxPzhTeGimbsbRDSnEoszhF937M4sDLLeS7Cu/Tmw==", + "integrity": "sha1-iIIYHgIsOL1GouTRjUTRnZCpD7I=", "dev": true, "requires": { "throat": "4.1.0" @@ -4238,7 +4268,7 @@ "jest-diff": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.3.tgz", - "integrity": "sha512-/QqGvCDP5oZOF6PebDuLwrB2BMD8ffJv6TAGAdEVuDx1+uEgrHpSFrfrOiMRx2eJ1hgNjlQrOQEHetVwij90KA==", + "integrity": "sha1-4YzD/v8K7vFZ0CMQ8mhtQGU3gDA=", "dev": true, "requires": { "chalk": "2.3.2", @@ -4250,7 +4280,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4287,7 +4317,7 @@ "jest-docblock": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-22.4.3.tgz", - "integrity": "sha512-uPKBEAw7YrEMcXueMKZXn/rbMxBiSv48fSqy3uEnmgOlQhSX+lthBqHb1fKWNVmFqAp9E/RsSdBfiV31LbzaOg==", + "integrity": "sha1-UIhvEytCsoDJA8WSNzu26Tu2ixk=", "dev": true, "requires": { "detect-newline": "2.1.0" @@ -4296,7 +4326,7 @@ "jest-environment-jsdom": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", - "integrity": "sha512-FviwfR+VyT3Datf13+ULjIMO5CSeajlayhhYQwpzgunswoaLIPutdbrnfUHEMyJCwvqQFaVtTmn9+Y8WCt6n1w==", + "integrity": "sha1-1n2qQVXjNRauzdNa/YLUq/D6ih4=", "dev": true, "requires": { "jest-mock": "22.4.3", @@ -4307,7 +4337,7 @@ "jest-environment-node": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-22.4.3.tgz", - "integrity": "sha512-reZl8XF6t/lMEuPWwo9OLfttyC26A5AMgDyEQ6DBgZuyfyeNUzYT8BFo6uxCCP/Av/b7eb9fTi3sIHFPBzmlRA==", + "integrity": "sha1-VMTqo3TIPdUqnah1m+FOvh0LkSk=", "dev": true, "requires": { "jest-mock": "22.4.3", @@ -4317,13 +4347,13 @@ "jest-get-type": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", + "integrity": "sha1-46hQTYR5NC3UQgI2syKGnxiQDOQ=", "dev": true }, "jest-haste-map": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-22.4.3.tgz", - "integrity": "sha512-4Q9fjzuPVwnaqGKDpIsCSoTSnG3cteyk2oNVjBX12HHOaF1oxql+uUiqZb5Ndu7g/vTZfdNwwy4WwYogLh29DQ==", + "integrity": "sha1-JYQvoro1AgB2esJ/ZY1YudXC4gs=", "dev": true, "requires": { "fb-watchman": "2.0.0", @@ -4394,7 +4424,7 @@ "jest-leak-detector": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-22.4.3.tgz", - "integrity": "sha512-NZpR/Ls7+ndO57LuXROdgCGz2RmUdC541tTImL9bdUtU3WadgFGm0yV+Ok4Fuia/1rLAn5KaJ+i76L6e3zGJYQ==", + "integrity": "sha1-K3smMQOvroxStrkSQaLeQBF+WzU=", "dev": true, "requires": { "pretty-format": "22.4.3" @@ -4403,7 +4433,7 @@ "jest-matcher-utils": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz", - "integrity": "sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA==", + "integrity": "sha1-RjL+Qo68c+vBlNPHtl03sWH3EP8=", "dev": true, "requires": { "chalk": "2.3.2", @@ -4414,7 +4444,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4451,7 +4481,7 @@ "jest-message-util": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.3.tgz", - "integrity": "sha512-iAMeKxhB3Se5xkSjU0NndLLCHtP4n+GtCqV0bISKA5dmOXQfEbdEmYiu2qpnWBDCQdEafNDDU6Q+l6oBMd/+BA==", + "integrity": "sha1-zz04qv5L792/xFXlfWXVI545nrc=", "dev": true, "requires": { "@babel/code-frame": "7.0.0-beta.42", @@ -4464,7 +4494,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4501,19 +4531,19 @@ "jest-mock": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-22.4.3.tgz", - "integrity": "sha512-+4R6mH5M1G4NK16CKg9N1DtCaFmuxhcIqF4lQK/Q1CIotqMs/XBemfpDPeVZBFow6iyUNu6EBT9ugdNOTT5o5Q==", + "integrity": "sha1-9jui8HoVEXcs3Hl5czOX33cKq8c=", "dev": true }, "jest-regex-util": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.4.3.tgz", - "integrity": "sha512-LFg1gWr3QinIjb8j833bq7jtQopiwdAs67OGfkPrvy7uNUbVMfTXXcOKXJaeY5GgjobELkKvKENqq1xrUectWg==", + "integrity": "sha1-qCbrGRzfIlAhmMVAGh/ATenO9a8=", "dev": true }, "jest-resolve": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-22.4.3.tgz", - "integrity": "sha512-u3BkD/MQBmwrOJDzDIaxpyqTxYH+XqAXzVJP51gt29H8jpj3QgKof5GGO2uPGKGeA1yTMlpbMs1gIQ6U4vcRhw==", + "integrity": "sha1-DOnUOMhDgimqm5FpaOxrBcGrtOo=", "dev": true, "requires": { "browser-resolve": "1.11.2", @@ -4523,7 +4553,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4560,7 +4590,7 @@ "jest-resolve-dependencies": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-22.4.3.tgz", - "integrity": "sha512-06czCMVToSN8F2U4EvgSB1Bv/56gc7MpCftZ9z9fBgUQM7dzHGCMBsyfVA6dZTx8v0FDcnALf7hupeQxaBCvpA==", + "integrity": "sha1-4iVqWoRnMtw5acty88mtdyWoGV4=", "dev": true, "requires": { "jest-regex-util": "22.4.3" @@ -4735,13 +4765,13 @@ "jest-serializer": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-22.4.3.tgz", - "integrity": "sha512-uPaUAppx4VUfJ0QDerpNdF43F68eqKWCzzhUlKNDsUPhjOon7ZehR4C809GCqh765FoMRtTVUVnGvIoskkYHiw==", + "integrity": "sha1-pnm4Gn8RHkdmI19PDEbSMO4PdDY=", "dev": true }, "jest-snapshot": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-22.4.3.tgz", - "integrity": "sha512-JXA0gVs5YL0HtLDCGa9YxcmmV2LZbwJ+0MfyXBBc5qpgkEYITQFJP7XNhcHFbUvRiniRpRbGVfJrOoYhhGE0RQ==", + "integrity": "sha1-tcm0KEb/ufrMt2uEExW6Z4hzYtI=", "dev": true, "requires": { "chalk": "2.3.2", @@ -4755,7 +4785,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4792,7 +4822,7 @@ "jest-util": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-22.4.3.tgz", - "integrity": "sha512-rfDfG8wyC5pDPNdcnAlZgwKnzHvZDu8Td2NJI/jAGKEGxJPYiE4F0ss/gSAkG4778Y23Hvbz+0GMrDJTeo7RjQ==", + "integrity": "sha1-xw/sjuxIfDexCwgJ3AZKfs9qr6w=", "dev": true, "requires": { "callsites": "2.0.0", @@ -4807,7 +4837,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -4839,7 +4869,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true }, "supports-color": { @@ -4906,7 +4936,7 @@ "jest-worker": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-22.4.3.tgz", - "integrity": "sha512-B1ucW4fI8qVAuZmicFxI1R3kr2fNeYJyvIQ1rKcuLYnenFV5K5aMbxFj6J0i00Ju83S8jP2d7Dz14+AvbIHRYQ==", + "integrity": "sha1-XEIUF8uhwKv2S/Vr1ft5aNed1As=", "dev": true, "requires": { "merge-stream": "1.0.1" @@ -5256,7 +5286,7 @@ "logform": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", - "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", + "integrity": "sha1-ydVZhxTJK1RuI/TngUfEDx4CAS4=", "requires": { "colors": "^1.2.1", "fast-safe-stringify": "^2.0.4", @@ -5273,7 +5303,7 @@ "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" } } }, @@ -5349,7 +5379,7 @@ "markdown-it-attrs": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-2.3.2.tgz", - "integrity": "sha512-DyatNvpatg7w+fGkplWGeie7o/0TogBr2w0izyz9ZQfTMv5G3lbDHQFQ42aP2e5L2mJQt0IeAjWzvYaa2d9xzQ==" + "integrity": "sha1-cGjEBXFzXhsPXEEqyAJiep/Q2wE=" }, "markdown-it-emoji": { "version": "1.4.0", @@ -5489,7 +5519,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "1.1.8" } @@ -5502,7 +5532,7 @@ "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { "for-in": "1.0.2", @@ -5512,7 +5542,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "2.0.4" @@ -5786,7 +5816,7 @@ "object-hash": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" + "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=" }, "object-keys": { "version": "1.0.11", @@ -5987,7 +6017,7 @@ "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "integrity": "sha1-bXhlbj2o14tOwLkG98CO8d/j9gg=", "dev": true }, "parseurl": { @@ -6097,13 +6127,13 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", "dev": true }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "integrity": "sha1-4vTO8OIZ9GPBeas3Rj5OHs3Muvs=", "dev": true }, "posix-character-classes": { @@ -6123,10 +6153,25 @@ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, + "prettier": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-format": { "version": "22.4.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.3.tgz", - "integrity": "sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==", + "integrity": "sha1-+HPXgIOanALpZkyKCC6e556qwW8=", "dev": true, "requires": { "ansi-regex": "3.0.0", @@ -6142,7 +6187,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "1.9.1" @@ -6153,7 +6198,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", "dev": true }, "process-nextick-args": { @@ -6304,7 +6349,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true }, "regex-cache": { @@ -6319,7 +6364,7 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { "extend-shallow": "3.0.2", @@ -6490,7 +6535,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, "right-align": { @@ -6863,7 +6908,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", "dev": true }, "semver": { @@ -6955,7 +7000,7 @@ "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { "extend-shallow": "2.0.1", @@ -6998,7 +7043,7 @@ "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", "dev": true }, "sigmund": { @@ -7021,7 +7066,7 @@ "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0" @@ -7038,7 +7083,7 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { "base": "0.11.2", @@ -7131,7 +7176,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "1.0.0", @@ -7159,7 +7204,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "3.2.2" @@ -7248,7 +7293,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { "extend-shallow": "3.0.2" @@ -7479,7 +7524,7 @@ "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", "dev": true, "requires": { "ajv": "5.5.2", @@ -7525,7 +7570,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -7939,7 +7984,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "1.0.2" @@ -7969,7 +8014,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { "define-property": "2.0.2", @@ -8034,7 +8079,7 @@ "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + "integrity": "sha1-pZUhTHKY24M57u7gg+TRC9jLjdk=" }, "tunnel-agent": { "version": "0.6.0", @@ -8266,7 +8311,7 @@ "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "requires": { "define-properties": "1.1.2", @@ -8357,7 +8402,7 @@ "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "integrity": "sha1-qFWYCx8LazWbodXZ+zmulB+qY60=", "dev": true }, "websocket-driver": { @@ -8416,7 +8461,7 @@ "winston": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", - "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "integrity": "sha1-oB5NHQoQPPTq2m/B+IazEQ1xw0s=", "requires": { "async": "1.0.0", "colors": "1.0.3", @@ -8441,7 +8486,7 @@ "winston-compat": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/winston-compat/-/winston-compat-0.1.4.tgz", - "integrity": "sha512-mMEfFsSm6GmkFF+f4/0UJtG4N1vSaczGmXLVJYmS/+u2zUaIPcw2ZRuwUg2TvVBjswgiraN+vNnAG8z4fRUZ4w==", + "integrity": "sha1-WZtM6Af/5yhxPswl7eP2uJQltzk=", "requires": { "cycle": "~1.0.3", "logform": "^1.6.0", @@ -8471,7 +8516,7 @@ "winston-transport": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", - "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "integrity": "sha1-32jAwgJILESNm0cxPAcwTC18LGY=", "requires": { "readable-stream": "^2.3.6", "triple-beam": "^1.2.0" @@ -8559,7 +8604,7 @@ "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "integrity": "sha1-auc+Bt5NjG5H+fsYH3jWSK1FfGo=", "dev": true }, "xtend": { @@ -8595,7 +8640,7 @@ "yargs-parser": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", - "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "integrity": "sha1-8TdqM7Ziml0GN4KUTacyYx6WaVA=", "dev": true, "requires": { "camelcase": "4.1.0"