From f72bf4cc9a27faa06a7d8dd85e953b8f4cf5ee19 Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Thu, 21 May 2020 23:36:18 -0700 Subject: [PATCH 01/14] allow the user's $docsify config to be a function that receives as input the Docsify instance --- src/core/config.js | 6 ++++-- src/core/init/index.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/config.js b/src/core/config.js index c35179059..981f4d018 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -2,7 +2,7 @@ import { merge, hyphenate, isPrimitive, hasOwn } from './util/core'; const currentScript = document.currentScript; -export default function() { +export default function(vm) { const config = merge( { el: '#app', @@ -35,7 +35,9 @@ export default function() { relativePath: false, topMargin: 0, }, - window.$docsify + typeof window.$docsify === 'function' + ? window.$docsify(vm) + : window.$docsify ); const script = diff --git a/src/core/init/index.js b/src/core/init/index.js index 9231acc1d..255aad06c 100644 --- a/src/core/init/index.js +++ b/src/core/init/index.js @@ -9,7 +9,7 @@ import { initLifecycle, callHook } from './lifecycle'; export function initMixin(proto) { proto._init = function() { const vm = this; - vm.config = config(); + vm.config = config(vm); initLifecycle(vm); // Init hooks initPlugin(vm); // Install plugins From b4b8bdc93e8197509b1aee002342bd7370c4069b Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Fri, 22 May 2020 01:28:34 -0700 Subject: [PATCH 02/14] add tests to make sure the global and plugin APIs are available and that configs can be functions --- src/core/index.js | 6 +-- test/_helper.js | 23 ++++++--- test/unit/docsify.test.js | 101 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 test/unit/docsify.test.js diff --git a/src/core/index.js b/src/core/index.js index 14f5d9422..2a90e3a4c 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -11,7 +11,7 @@ import initGlobalAPI from './global-api'; * @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback, * otherwise it only attaches the callback to the DOMContentLoaded event */ -function ready(callback) { +export function documentReady(callback) { const state = document.readyState; if (state === 'complete' || state === 'interactive') { @@ -21,7 +21,7 @@ function ready(callback) { document.addEventListener('DOMContentLoaded', callback); } -function Docsify() { +export function Docsify() { this._init(); } @@ -42,4 +42,4 @@ initGlobalAPI(); * Run Docsify */ // eslint-disable-next-line no-unused-vars -ready(_ => new Docsify()); +documentReady(_ => new Docsify()); diff --git a/test/_helper.js b/test/_helper.js index afd0c07fd..39ee5bdb1 100644 --- a/test/_helper.js +++ b/test/_helper.js @@ -19,6 +19,21 @@ function ready(callback) { document.addEventListener('DOMContentLoaded', callback); } +module.exports.initJSDOM = initJSDOM; + +/** @param {string} markup - The HTML document to initialize JSDOM with. */ +function initJSDOM(markup, options = {}) { + const dom = new JSDOM(markup, options); + + global.window = dom.window; + global.document = dom.window.document; + global.navigator = dom.window.navigator; + global.location = dom.window.location; + global.XMLHttpRequest = dom.window.XMLHttpRequest; + + return dom; +} + module.exports.init = function( fixture = 'default', config = {}, @@ -39,15 +54,9 @@ module.exports.init = function( const rootPath = path.join(__dirname, 'fixtures', fixture); - const dom = new JSDOM(markup); + const dom = initJSDOM(markup); dom.reconfigure({ url: 'file:///' + rootPath }); - global.window = dom.window; - global.document = dom.window.document; - global.navigator = dom.window.navigator; - global.location = dom.window.location; - global.XMLHttpRequest = dom.window.XMLHttpRequest; - // Mimic src/core/index.js but for Node.js function Docsify() { this._init(); diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js new file mode 100644 index 000000000..5d78fed7c --- /dev/null +++ b/test/unit/docsify.test.js @@ -0,0 +1,101 @@ +/* eslint-disable no-global-assign */ +require = require('esm')(module /* , options */); + +const path = require('path'); +const { expect } = require('chai'); +const { initJSDOM } = require('../_helper'); + +const docsifySite = path.join(__dirname, '..', '..', 'docs'); + +const markup = /* html */ ` + + + +
+ + +`; + +describe('Docsify public API', () => { + it('is available', async () => { + const DOM = initJSDOM(markup); + DOM.reconfigure({ url: 'file:///' + docsifySite }); + + const { documentReady } = require('../../src/core/index'); + await new Promise(resolve => documentReady(resolve)); + + expect(typeof window.Docsify).to.equal('object'); + expect(typeof window.Docsify.util).to.equal('object'); + expect(typeof window.Docsify.dom).to.equal('object'); + expect(typeof window.Docsify.get).to.equal('function'); + expect(typeof window.Docsify.slugify).to.equal('function'); + expect(typeof window.Docsify.version).to.equal('string'); + + expect(window.DocsifyCompiler).to.be.an.instanceof(Function); + expect(window.marked).to.be.an.instanceof(Function); + expect(typeof window.Prism).to.equal('object'); + }); +}); + +describe('Docsify config function', function() { + it('allows $docsify to be a function', async function() { + const DOM = initJSDOM(markup); + DOM.reconfigure({ url: 'file:///' + docsifySite }); + + window.configFunctionCalled = false; + + window.$docsify = function(vm) { + // Check public API (that which is available at this point) + expect(vm).to.be.an.instanceof(Object); + expect(vm.constructor.name).to.equal('Docsify'); + expect(vm.$fetch).to.be.an.instanceof(Function); + expect(vm.$resetEvents).to.be.an.instanceof(Function); + expect(vm.route).to.be.an.instanceof(Object); + + window.configFunctionCalled = true; + + return {}; + }; + + const { documentReady, Docsify } = require('../../src/core/index'); + await new Promise(resolve => documentReady(resolve)); + + new Docsify(); // eslint-disable-line + + expect(window.configFunctionCalled).to.equal(true); + }); + + it('provides the hooks and vm API to plugins', async function() { + const DOM = initJSDOM(markup); + DOM.reconfigure({ url: 'file:///' + docsifySite }); + + window.pluginFunctionCalled = false; + + window.$docsify = function(vm) { + const vm1 = vm; + return { + plugins: [ + function(hook, vm2) { + expect(vm1).to.equal(vm2); + + expect(hook.init).to.be.an.instanceof(Function); + expect(hook.beforeEach).to.be.an.instanceof(Function); + expect(hook.afterEach).to.be.an.instanceof(Function); + expect(hook.doneEach).to.be.an.instanceof(Function); + expect(hook.mounted).to.be.an.instanceof(Function); + expect(hook.ready).to.be.an.instanceof(Function); + + window.pluginFunctionCalled = true; + }, + ], + }; + }; + + const { documentReady, Docsify } = require('../../src/core/index'); + await new Promise(resolve => documentReady(resolve)); + + new Docsify(); // eslint-disable-line + + expect(window.pluginFunctionCalled).to.equal(true); + }); +}); From 732c34db55f09e22bafce133a6492f25fa8ef1d5 Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Fri, 22 May 2020 01:28:56 -0700 Subject: [PATCH 03/14] add editorconfig (tells editors which basic text format to use) --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..80f989d97 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# http://EditorConfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true From 5a5b5aa932ede41d34f86cd087f237248558c605 Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Fri, 22 May 2020 01:42:40 -0700 Subject: [PATCH 04/14] update docs regarding configs as functions --- docs/configuration.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index d402384f0..03b262edf 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,6 +1,6 @@ # Configuration -You can configure the `window.$docsify`. +You can configure Docsify by defining `window.$docsify` as an object: ```html ``` +The config can also be defined as a function, in which case the first arg is the Docsify `vm` instance. The function should return a config object. This can be useful for referencing `vm` in places like the markdown configuration: + +```html + +``` + ## el - Type: `String` From b72cb3d94c8fc4d8f67b29bf32d0f3b3f663e3bb Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Fri, 22 May 2020 23:59:25 -0700 Subject: [PATCH 05/14] add build error handling so builds don't silently fail --- build/build.js | 111 +++++++++++++++++++++++++++--------------------- build/css.js | 13 ++++-- build/mincss.js | 3 ++ build/ssr.js | 3 +- 4 files changed, 78 insertions(+), 52 deletions(-) diff --git a/build/build.js b/build/build.js index 6fa2b123b..02bc23b57 100644 --- a/build/build.js +++ b/build/build.js @@ -9,8 +9,8 @@ const version = process.env.VERSION || require('../package.json').version const chokidar = require('chokidar') const path = require('path') -const build = function (opts) { - rollup +async function build(opts) { + await rollup .rollup({ input: opts.input, plugins: (opts.plugins || []).concat([ @@ -27,31 +27,34 @@ const build = function (opts) { var dest = 'lib/' + (opts.output || opts.input) console.log(dest) - bundle.write({ + return bundle.write({ format: 'iife', file: dest, strict: false }) }) - .catch(function (err) { - console.error(err) - }) } -const buildCore = function () { - build({ + +async function buildCore() { + const promises = [] + + promises.push(build({ input: 'src/core/index.js', output: 'docsify.js' - }) + })) if (isProd) { - build({ + promises.push(build({ input: 'src/core/index.js', output: 'docsify.min.js', plugins: [uglify()] - }) + })) } + + await Promise.all(promises) } -const buildAllPlugin = function () { + +async function buildAllPlugin() { var plugins = [ {name: 'search', input: 'search/index.js'}, {name: 'ga', input: 'ga.js'}, @@ -64,8 +67,8 @@ const buildAllPlugin = function () { {name: 'gitalk', input: 'gitalk.js'} ] - plugins.forEach(item => { - build({ + const promises = plugins.map(item => { + return build({ input: 'src/plugins/' + item.input, output: 'plugins/' + item.name + '.js' }) @@ -73,47 +76,59 @@ const buildAllPlugin = function () { if (isProd) { plugins.forEach(item => { - build({ + promises.push(build({ input: 'src/plugins/' + item.input, output: 'plugins/' + item.name + '.min.js', plugins: [uglify()] - }) + })) }) } + + await Promise.all(promises) } -if (!isProd) { - chokidar - .watch(['src/core', 'src/plugins'], { - atomic: true, - awaitWriteFinish: { - stabilityThreshold: 1000, - pollInterval: 100 - } - }) - .on('change', p => { - console.log('[watch] ', p) - const dirs = p.split(path.sep) - if (dirs[1] === 'core') { - buildCore() - } else if (dirs[2]) { - const name = path.basename(dirs[2], '.js') - const input = `src/plugins/${name}${ - /\.js/.test(dirs[2]) ? '' : '/index' - }.js` +async function main() { + if (!isProd) { + chokidar + .watch(['src/core', 'src/plugins'], { + atomic: true, + awaitWriteFinish: { + stabilityThreshold: 1000, + pollInterval: 100 + } + }) + .on('change', p => { + console.log('[watch] ', p) + const dirs = p.split(path.sep) + if (dirs[1] === 'core') { + buildCore() + } else if (dirs[2]) { + const name = path.basename(dirs[2], '.js') + const input = `src/plugins/${name}${ + /\.js/.test(dirs[2]) ? '' : '/index' + }.js` - build({ - input, - output: 'plugins/' + name + '.js' - }) - } - }) - .on('ready', () => { - console.log('[start]') - buildCore() + build({ + input, + output: 'plugins/' + name + '.js' + }) + } + }) + .on('ready', () => { + console.log('[start]') + buildCore() + buildAllPlugin() + }) + } else { + await Promise.all([ + buildCore(), buildAllPlugin() - }) -} else { - buildCore() - buildAllPlugin() + ]) + } } + +main().catch((e) => { + console.error(e) + process.exit(1) +}) + diff --git a/build/css.js b/build/css.js index 060506421..3ae9701fe 100644 --- a/build/css.js +++ b/build/css.js @@ -5,8 +5,8 @@ const {spawn} = require('child_process') const args = process.argv.slice(2) fs.readdir(path.join(__dirname, '../src/themes'), (err, files) => { if (err) { - console.log('err', err) - return + console.error('err', err) + process.exit(1) } files.map(async (file) => { if (/\.styl/g.test(file)) { @@ -31,7 +31,14 @@ fs.readdir(path.join(__dirname, '../src/themes'), (err, files) => { }); stylusCMD.on('close', (code) => { - console.log(`[Stylus Build ] child process exited with code ${code}`); + const message = `[Stylus Build ] child process exited with code ${code}` + + if (code !== 0) { + console.error(message); + process.exit(code) + } else { + console.log(message); + } }); } else { return diff --git a/build/mincss.js b/build/mincss.js index f6c5ec215..0c9c72280 100644 --- a/build/mincss.js +++ b/build/mincss.js @@ -8,5 +8,8 @@ files.forEach(file => { file = path.resolve('lib/themes', file) cssnano(fs.readFileSync(file)).then(result => { fs.writeFileSync(file, result.css) + }).catch(e => { + console.error(e) + process.exit(1) }) }) diff --git a/build/ssr.js b/build/ssr.js index 16b93cac4..01fdd0518 100644 --- a/build/ssr.js +++ b/build/ssr.js @@ -24,11 +24,12 @@ rollup var dest = 'packages/docsify-server-renderer/build.js' console.log(dest) - bundle.write({ + return bundle.write({ format: 'cjs', file: dest }) }) .catch(function (err) { console.error(err) + process.exit(1) }) From 7e002bf939d7837843908417b5445b4f8d36c1cd Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sat, 23 May 2020 13:55:05 -0700 Subject: [PATCH 06/14] feat: update src/core/index.js to export all global APIs, deprecate old globals in favor of a single global DOCSIFY, and add tests for this --- build/build.js | 13 +- package-lock.json | 441 +++++++++++++++++++++++++++----------- package.json | 3 +- src/core/global-api.js | 8 +- src/core/index.js | 31 ++- src/core/util/dom.js | 16 ++ test/unit/docsify.test.js | 182 ++++++++++------ 7 files changed, 478 insertions(+), 216 deletions(-) diff --git a/build/build.js b/build/build.js index 02bc23b57..7916b08ee 100644 --- a/build/build.js +++ b/build/build.js @@ -9,6 +9,14 @@ const version = process.env.VERSION || require('../package.json').version const chokidar = require('chokidar') const path = require('path') +/** + * @param {{ + * input: string, + * output?: string, + * globalName?: string, + * plugins?: Array + * }} opts + */ async function build(opts) { await rollup .rollup({ @@ -29,6 +37,7 @@ async function build(opts) { console.log(dest) return bundle.write({ format: 'iife', + output: opts.globalName ? {name: opts.globalName} : {}, file: dest, strict: false }) @@ -40,13 +49,15 @@ async function buildCore() { promises.push(build({ input: 'src/core/index.js', - output: 'docsify.js' + output: 'docsify.js', + globalName: 'DOCSIFY' })) if (isProd) { promises.push(build({ input: 'src/core/index.js', output: 'docsify.min.js', + globalName: 'DOCSIFY', plugins: [uglify()] })) } diff --git a/package-lock.json b/package-lock.json index 58a81e284..404c907fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1739,9 +1739,9 @@ } }, "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, "abbrev": { @@ -1773,13 +1773,21 @@ "dev": true }, "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "dev": true + } } }, "acorn-jsx": { @@ -1789,9 +1797,9 @@ "dev": true }, "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", "dev": true }, "add-stream": { @@ -2014,12 +2022,6 @@ "integrity": "sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w==", "dev": true }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -2292,12 +2294,6 @@ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, "async-to-gen": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/async-to-gen/-/async-to-gen-1.4.0.tgz", @@ -2534,9 +2530,9 @@ } }, "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, "browser-stdout": { @@ -2637,6 +2633,12 @@ "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, "cacache": { "version": "12.0.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", @@ -3203,6 +3205,12 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, "conventional-changelog": { "version": "3.1.12", "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.12.tgz", @@ -3723,18 +3731,26 @@ } }, "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "requires": { - "cssom": "0.3.x" + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } } }, "currently-unhandled": { @@ -4231,14 +4247,42 @@ } }, "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + }, + "whatwg-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", + "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^5.0.0" + } + } } }, "date-fns": { @@ -4292,6 +4336,12 @@ } } }, + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", + "dev": true + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -4584,12 +4634,20 @@ "dev": true }, "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "requires": { - "webidl-conversions": "^4.0.2" + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } } }, "domutils": { @@ -4803,24 +4861,16 @@ "dev": true }, "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", "dev": true, "requires": { - "esprima": "^3.1.3", + "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - } } }, "eslint": { @@ -5588,6 +5638,23 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "dev": true, + "requires": { + "punycode": "^1.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, "fastq": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", @@ -6640,12 +6707,12 @@ "dev": true }, "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^1.0.5" } }, "http-auth": { @@ -7288,6 +7355,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -7546,37 +7619,119 @@ "dev": true }, "jsdom": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz", - "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^6.1.1", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.3.6", - "cssstyle": "^1.2.2", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.1.4", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", + "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.0.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "dev": true + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "tr46": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", + "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + } } }, "jsesc": { @@ -9839,9 +9994,9 @@ "dev": true }, "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, "oauth-sign": { @@ -10419,9 +10574,9 @@ } }, "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", "dev": true }, "parseurl": { @@ -10472,6 +10627,12 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -10633,12 +10794,6 @@ "xmldom": "0.1.x" } }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, "pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -11627,21 +11782,21 @@ } }, "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.15" } }, "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", "dev": true, "requires": { - "request-promise-core": "1.1.2", + "request-promise-core": "1.1.3", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" }, @@ -12005,12 +12160,12 @@ "dev": true }, "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, "requires": { - "xmlchars": "^2.1.1" + "xmlchars": "^2.2.0" } }, "select": { @@ -12083,6 +12238,45 @@ "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, + "serve-handler": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.2.tgz", + "integrity": "sha512-RFh49wX7zJmmOVDcIjiDSJnMH+ItQEvyuYLYuDBVoA/xmQSCuj+uRmk1cmBB5QQlI3qOiWKp6p4DUGY+Z5AB2A==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + }, + "dependencies": { + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "~1.33.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + } + } + }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -13612,22 +13806,20 @@ "dev": true }, "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", "dev": true, "requires": { - "browser-process-hrtime": "^0.1.2" + "browser-process-hrtime": "^1.0.0" } }, "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dev": true, "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", "xml-name-validator": "^3.0.0" } }, @@ -13962,13 +14154,10 @@ } }, "ws": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz", - "integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==", - "dev": true, - "requires": { - "async-limiter": "^1.0.0" - } + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index 695e960fc..02fd700bd 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "eslint-plugin-prettier": "^3.1.2", "esm": "^3.1.4", "husky": "^3.1.0", - "jsdom": "^15.1.1", + "jsdom": "^16.2.2", "lerna": "^3.17.0", "lint-staged": "^9.5.0", "live-server": "^1.2.1", @@ -100,6 +100,7 @@ "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0", "rollup-plugin-uglify": "^6.0.4", + "serve-handler": "^6.1.2", "start-server-and-test": "^1.10.6", "stylus": "^0.54.5" }, diff --git a/src/core/global-api.js b/src/core/global-api.js index 5529bdaf3..a5f69f6f8 100644 --- a/src/core/global-api.js +++ b/src/core/global-api.js @@ -1,11 +1,15 @@ +import prism from 'prismjs'; +import marked from 'marked'; import * as util from './util'; import * as dom from './util/dom'; import { Compiler } from './render/compiler'; import { slugify } from './render/slugify'; import { get } from './fetch/ajax'; -import prism from 'prismjs'; -import marked from 'marked'; +// TODO This is deprecated, kept for backwards compatibility. Remove in next +// major release. We'll tell people to get everything from the DOCSIFY global +// when using the global build, but we'll highly recommend for them to import +// from the ESM build (f.e. lib/docsify.esm.js and lib/docsify.min.esm.js). export default function() { window.Docsify = { util, diff --git a/src/core/index.js b/src/core/index.js index 2a90e3a4c..220d2d295 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,25 +1,16 @@ +import Prism from 'prismjs'; +import marked from 'marked'; import { initMixin } from './init'; import { routerMixin } from './router'; import { renderMixin } from './render'; import { fetchMixin } from './fetch'; import { eventMixin } from './event'; import initGlobalAPI from './global-api'; - -/** - * Fork https://github.com/bendrucker/document-ready/blob/master/index.js - * @param {Function} callback The callbacack to be called when the page is loaded - * @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback, - * otherwise it only attaches the callback to the DOMContentLoaded event - */ -export function documentReady(callback) { - const state = document.readyState; - - if (state === 'complete' || state === 'interactive') { - return setTimeout(callback, 0); - } - - document.addEventListener('DOMContentLoaded', callback); -} +import { Compiler as DocsifyCompiler } from './render/compiler'; +import * as util from './util'; +import * as dom from './util/dom'; +import { slugify } from './render/slugify'; +import { get } from './fetch/ajax'; export function Docsify() { this._init(); @@ -36,10 +27,14 @@ eventMixin(proto); /** * Global API */ -initGlobalAPI(); +initGlobalAPI(); // deprecated + +// Rollup assigns all exports from this file onto a single DOCSIFY global. +export { util, dom, get, slugify, DocsifyCompiler, marked, Prism }; +export const version = '__VERSION__'; /** * Run Docsify */ // eslint-disable-next-line no-unused-vars -documentReady(_ => new Docsify()); +dom.documentReady(_ => new Docsify()); diff --git a/src/core/util/dom.js b/src/core/util/dom.js index b17628636..c0eb9831e 100644 --- a/src/core/util/dom.js +++ b/src/core/util/dom.js @@ -101,3 +101,19 @@ export function toggleClass(el, type, val) { export function style(content) { appendTo(head, create('style', content)); } + +/** + * Fork https://github.com/bendrucker/document-ready/blob/master/index.js + * @param {Function} callback The callbacack to be called when the page is loaded + * @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback, + * otherwise it only attaches the callback to the DOMContentLoaded event + */ +export function documentReady(callback, doc = document) { + const state = doc.readyState; + + if (state === 'complete' || state === 'interactive') { + return setTimeout(callback, 0); + } + + doc.addEventListener('DOMContentLoaded', callback); +} diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js index 5d78fed7c..f9796633f 100644 --- a/test/unit/docsify.test.js +++ b/test/unit/docsify.test.js @@ -1,101 +1,147 @@ +/* global before after */ /* eslint-disable no-global-assign */ require = require('esm')(module /* , options */); -const path = require('path'); +const http = require('http'); +const handler = require('serve-handler'); const { expect } = require('chai'); const { initJSDOM } = require('../_helper'); -const docsifySite = path.join(__dirname, '..', '..', 'docs'); +const docsifySite = 'http://127.0.0.1:3000'; const markup = /* html */ `
+ + `; +/** @type {ReturnType} */ +let server; + describe('Docsify public API', () => { - it('is available', async () => { - const DOM = initJSDOM(markup); - DOM.reconfigure({ url: 'file:///' + docsifySite }); - - const { documentReady } = require('../../src/core/index'); - await new Promise(resolve => documentReady(resolve)); - - expect(typeof window.Docsify).to.equal('object'); - expect(typeof window.Docsify.util).to.equal('object'); - expect(typeof window.Docsify.dom).to.equal('object'); - expect(typeof window.Docsify.get).to.equal('function'); - expect(typeof window.Docsify.slugify).to.equal('function'); - expect(typeof window.Docsify.version).to.equal('string'); - - expect(window.DocsifyCompiler).to.be.an.instanceof(Function); - expect(window.marked).to.be.an.instanceof(Function); - expect(typeof window.Prism).to.equal('object'); + before(async () => { + server = http.createServer((request, response) => { + // You pass two more arguments for config and middleware + // More details here: https://github.com/zeit/serve-handler#options + return handler(request, response); + }); + + await new Promise(r => server.listen(3000, r)); }); -}); -describe('Docsify config function', function() { - it('allows $docsify to be a function', async function() { - const DOM = initJSDOM(markup); - DOM.reconfigure({ url: 'file:///' + docsifySite }); + after(async () => { + server.close(err => { + if (err) { + console.error(err); // eslint-disable-line + process.exit(1); + } + // eslint-disable-next-line + console.log('Server closed.'); + }); + }); - window.configFunctionCalled = false; + it('global APIs are available', async () => { + // const DOM = new (require('jsdom').JSDOM)(markup, { + const DOM = initJSDOM(markup, { + url: docsifySite, + runScripts: 'dangerously', + resources: 'usable', + }); + + const { documentReady } = require('../../src/core/util/dom'); + await new Promise(resolve => documentReady(resolve, DOM.window.document)); + + // deprecated global API, still works for now, backwards comaptible + expect(typeof DOM.window.Docsify).to.equal('object'); + expect(typeof DOM.window.Docsify.util).to.equal('object'); + expect(typeof DOM.window.Docsify.dom).to.equal('object'); + expect(typeof DOM.window.Docsify.get).to.equal('function'); + expect(typeof DOM.window.Docsify.slugify).to.equal('function'); + expect(typeof DOM.window.Docsify.version).to.equal('string'); + expect(typeof DOM.window.DocsifyCompiler).to.equal('function'); + expect(typeof DOM.window.marked).to.equal('function'); + expect(typeof DOM.window.Prism).to.equal('object'); + + // new global API, everything under one namespace (DOCSIFY) + expect(typeof DOM.window.DOCSIFY).to.equal('object'); + expect(typeof DOM.window.DOCSIFY.Docsify).to.equal('function'); + expect(typeof DOM.window.DOCSIFY.util).to.equal('object'); + expect(typeof DOM.window.DOCSIFY.dom).to.equal('object'); + expect(typeof DOM.window.DOCSIFY.get).to.equal('function'); + expect(typeof DOM.window.DOCSIFY.slugify).to.equal('function'); + expect(typeof DOM.window.DOCSIFY.version).to.equal('string'); + expect(typeof DOM.window.DOCSIFY.DocsifyCompiler).to.equal('function'); + expect(typeof DOM.window.DOCSIFY.marked).to.equal('function'); + expect(typeof DOM.window.DOCSIFY.Prism).to.equal('object'); + }); - window.$docsify = function(vm) { - // Check public API (that which is available at this point) - expect(vm).to.be.an.instanceof(Object); - expect(vm.constructor.name).to.equal('Docsify'); - expect(vm.$fetch).to.be.an.instanceof(Function); - expect(vm.$resetEvents).to.be.an.instanceof(Function); - expect(vm.route).to.be.an.instanceof(Object); + describe('Docsify config function', function() { + it('allows $docsify to be a function', async function() { + initJSDOM(markup, { url: docsifySite }); - window.configFunctionCalled = true; + window.configFunctionCalled = false; - return {}; - }; + window.$docsify = function(vm) { + // Check public API (that which is available at this point) + expect(vm).to.be.an.instanceof(Object); + expect(vm.constructor.name).to.equal('Docsify'); + expect(vm.$fetch).to.be.an.instanceof(Function); + expect(vm.$resetEvents).to.be.an.instanceof(Function); + expect(vm.route).to.be.an.instanceof(Object); - const { documentReady, Docsify } = require('../../src/core/index'); - await new Promise(resolve => documentReady(resolve)); + window.configFunctionCalled = true; - new Docsify(); // eslint-disable-line + return {}; + }; - expect(window.configFunctionCalled).to.equal(true); - }); + const { documentReady } = require('../../src/core/util/dom'); + const { Docsify } = require('../../src/core/index'); + await new Promise(resolve => documentReady(resolve)); + + new Docsify(); // eslint-disable-line + + expect(window.configFunctionCalled).to.equal(true); + }); + + it('provides the hooks and vm API to plugins', async function() { + initJSDOM(markup, { url: docsifySite }); + + window.pluginFunctionCalled = false; + + window.$docsify = function(vm) { + const vm1 = vm; + return { + plugins: [ + function(hook, vm2) { + expect(vm1).to.equal(vm2); + + expect(hook.init).to.be.an.instanceof(Function); + expect(hook.beforeEach).to.be.an.instanceof(Function); + expect(hook.afterEach).to.be.an.instanceof(Function); + expect(hook.doneEach).to.be.an.instanceof(Function); + expect(hook.mounted).to.be.an.instanceof(Function); + expect(hook.ready).to.be.an.instanceof(Function); - it('provides the hooks and vm API to plugins', async function() { - const DOM = initJSDOM(markup); - DOM.reconfigure({ url: 'file:///' + docsifySite }); - - window.pluginFunctionCalled = false; - - window.$docsify = function(vm) { - const vm1 = vm; - return { - plugins: [ - function(hook, vm2) { - expect(vm1).to.equal(vm2); - - expect(hook.init).to.be.an.instanceof(Function); - expect(hook.beforeEach).to.be.an.instanceof(Function); - expect(hook.afterEach).to.be.an.instanceof(Function); - expect(hook.doneEach).to.be.an.instanceof(Function); - expect(hook.mounted).to.be.an.instanceof(Function); - expect(hook.ready).to.be.an.instanceof(Function); - - window.pluginFunctionCalled = true; - }, - ], + window.pluginFunctionCalled = true; + }, + ], + }; }; - }; - const { documentReady, Docsify } = require('../../src/core/index'); - await new Promise(resolve => documentReady(resolve)); + const { documentReady } = require('../../src/core/util/dom'); + const { Docsify } = require('../../src/core/index'); + await new Promise(resolve => documentReady(resolve)); - new Docsify(); // eslint-disable-line + new Docsify(); // eslint-disable-line - expect(window.pluginFunctionCalled).to.equal(true); + expect(window.pluginFunctionCalled).to.equal(true); + }); }); }); From 88033b639eb5665514f8ea24ee668914f579a8a3 Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 11:09:06 -0700 Subject: [PATCH 07/14] remove the DOCSIFY global made by Rollup, and move Docsify into a separate file where we can import it from tests while leaving the entry point for the bundle without any exports so that Rollup will not create a global variable from it --- build/build.js | 2 -- src/core/Docsify.js | 23 +++++++++++++++++++++++ src/core/index.js | 34 +--------------------------------- test/unit/docsify.test.js | 16 ++-------------- 4 files changed, 26 insertions(+), 49 deletions(-) create mode 100644 src/core/Docsify.js diff --git a/build/build.js b/build/build.js index 7916b08ee..7dfa6b536 100644 --- a/build/build.js +++ b/build/build.js @@ -50,14 +50,12 @@ async function buildCore() { promises.push(build({ input: 'src/core/index.js', output: 'docsify.js', - globalName: 'DOCSIFY' })) if (isProd) { promises.push(build({ input: 'src/core/index.js', output: 'docsify.min.js', - globalName: 'DOCSIFY', plugins: [uglify()] })) } diff --git a/src/core/Docsify.js b/src/core/Docsify.js new file mode 100644 index 000000000..fcb40336b --- /dev/null +++ b/src/core/Docsify.js @@ -0,0 +1,23 @@ +import { initMixin } from './init'; +import { routerMixin } from './router'; +import { renderMixin } from './render'; +import { fetchMixin } from './fetch'; +import { eventMixin } from './event'; +import initGlobalAPI from './global-api'; + +export function Docsify() { + this._init(); +} + +const proto = Docsify.prototype; + +initMixin(proto); +routerMixin(proto); +renderMixin(proto); +fetchMixin(proto); +eventMixin(proto); + +/** + * Global API + */ +initGlobalAPI(); diff --git a/src/core/index.js b/src/core/index.js index 220d2d295..344bafdba 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,37 +1,5 @@ -import Prism from 'prismjs'; -import marked from 'marked'; -import { initMixin } from './init'; -import { routerMixin } from './router'; -import { renderMixin } from './render'; -import { fetchMixin } from './fetch'; -import { eventMixin } from './event'; -import initGlobalAPI from './global-api'; -import { Compiler as DocsifyCompiler } from './render/compiler'; -import * as util from './util'; import * as dom from './util/dom'; -import { slugify } from './render/slugify'; -import { get } from './fetch/ajax'; - -export function Docsify() { - this._init(); -} - -const proto = Docsify.prototype; - -initMixin(proto); -routerMixin(proto); -renderMixin(proto); -fetchMixin(proto); -eventMixin(proto); - -/** - * Global API - */ -initGlobalAPI(); // deprecated - -// Rollup assigns all exports from this file onto a single DOCSIFY global. -export { util, dom, get, slugify, DocsifyCompiler, marked, Prism }; -export const version = '__VERSION__'; +import { Docsify } from './Docsify'; /** * Run Docsify diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js index f9796633f..b1d95dfac 100644 --- a/test/unit/docsify.test.js +++ b/test/unit/docsify.test.js @@ -68,18 +68,6 @@ describe('Docsify public API', () => { expect(typeof DOM.window.DocsifyCompiler).to.equal('function'); expect(typeof DOM.window.marked).to.equal('function'); expect(typeof DOM.window.Prism).to.equal('object'); - - // new global API, everything under one namespace (DOCSIFY) - expect(typeof DOM.window.DOCSIFY).to.equal('object'); - expect(typeof DOM.window.DOCSIFY.Docsify).to.equal('function'); - expect(typeof DOM.window.DOCSIFY.util).to.equal('object'); - expect(typeof DOM.window.DOCSIFY.dom).to.equal('object'); - expect(typeof DOM.window.DOCSIFY.get).to.equal('function'); - expect(typeof DOM.window.DOCSIFY.slugify).to.equal('function'); - expect(typeof DOM.window.DOCSIFY.version).to.equal('string'); - expect(typeof DOM.window.DOCSIFY.DocsifyCompiler).to.equal('function'); - expect(typeof DOM.window.DOCSIFY.marked).to.equal('function'); - expect(typeof DOM.window.DOCSIFY.Prism).to.equal('object'); }); describe('Docsify config function', function() { @@ -102,7 +90,7 @@ describe('Docsify public API', () => { }; const { documentReady } = require('../../src/core/util/dom'); - const { Docsify } = require('../../src/core/index'); + const { Docsify } = require('../../src/core/Docsify'); await new Promise(resolve => documentReady(resolve)); new Docsify(); // eslint-disable-line @@ -136,7 +124,7 @@ describe('Docsify public API', () => { }; const { documentReady } = require('../../src/core/util/dom'); - const { Docsify } = require('../../src/core/index'); + const { Docsify } = require('../../src/core/Docsify'); await new Promise(resolve => documentReady(resolve)); new Docsify(); // eslint-disable-line From 79fe3d5c5e981828268181b83f4c83257944efdd Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 11:24:54 -0700 Subject: [PATCH 08/14] remove some unused code and accept eslint changes --- packages/docsify-server-renderer/index.js | 4 ++-- src/core/event/scroll.js | 2 +- src/core/render/compiler.js | 2 +- src/core/render/embed.js | 2 +- src/core/render/index.js | 2 +- test/unit/base.test.js | 2 +- test/unit/docsify.test.js | 3 --- test/unit/render.test.js | 2 +- test/unit/util.test.js | 2 +- 9 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/docsify-server-renderer/index.js b/packages/docsify-server-renderer/index.js index 0d87dffdd..e6f5f9666 100644 --- a/packages/docsify-server-renderer/index.js +++ b/packages/docsify-server-renderer/index.js @@ -1,13 +1,13 @@ import { readFileSync } from 'fs'; import { resolve, basename } from 'path'; import resolvePathname from 'resolve-pathname'; +import fetch from 'node-fetch'; +import debug from 'debug'; import { AbstractHistory } from '../../src/core/router/history/abstract'; import { Compiler } from '../../src/core/render/compiler'; import { isAbsolutePath } from '../../src/core/router/util'; import * as tpl from '../../src/core/render/tpl'; import { prerenderEmbed } from '../../src/core/render/embed'; -import fetch from 'node-fetch'; -import debug from 'debug'; function cwd(...args) { return resolve(process.cwd(), ...args); diff --git a/src/core/event/scroll.js b/src/core/event/scroll.js index ef78443ba..7458ec0a6 100644 --- a/src/core/event/scroll.js +++ b/src/core/event/scroll.js @@ -1,7 +1,7 @@ +import Tweezer from 'tweezer.js'; import { isMobile } from '../util/env'; import * as dom from '../util/dom'; import config from '../config'; -import Tweezer from 'tweezer.js'; const nav = {}; let hoverOver = false; diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index c4c026205..455d3512f 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -1,3 +1,4 @@ +import marked from 'marked'; import { isAbsolutePath, getPath, getParentPath } from '../router/util'; import { isFn, merge, cached, isPrimitive } from '../util/core'; import { tree as treeTpl } from './tpl'; @@ -11,7 +12,6 @@ import { paragraphCompiler } from './compiler/paragraph'; import { taskListCompiler } from './compiler/taskList'; import { taskListItemCompiler } from './compiler/taskListItem'; import { linkCompiler } from './compiler/link'; -import marked from 'marked'; const cachedLinks = {}; diff --git a/src/core/render/embed.js b/src/core/render/embed.js index 083fb7f97..b64d11a8b 100644 --- a/src/core/render/embed.js +++ b/src/core/render/embed.js @@ -1,6 +1,6 @@ +import stripIndent from 'strip-indent'; import { get } from '../fetch/ajax'; import { merge } from '../util/core'; -import stripIndent from 'strip-indent'; const cached = {}; diff --git a/src/core/render/index.js b/src/core/render/index.js index 9b50dc708..37cd6af34 100644 --- a/src/core/render/index.js +++ b/src/core/render/index.js @@ -1,4 +1,5 @@ /* eslint-disable no-unused-vars */ +import tinydate from 'tinydate'; import * as dom from '../util/dom'; import cssVars from '../util/polyfill/css-vars'; import { callHook } from '../init/lifecycle'; @@ -10,7 +11,6 @@ import { scrollActiveSidebar } from '../event/scroll'; import { Compiler } from './compiler'; import * as tpl from './tpl'; import { prerenderEmbed } from './embed'; -import tinydate from 'tinydate'; function executeScript() { const script = dom diff --git a/test/unit/base.test.js b/test/unit/base.test.js index 736b70ac6..ed050424a 100644 --- a/test/unit/base.test.js +++ b/test/unit/base.test.js @@ -2,8 +2,8 @@ require = require('esm')( module /* , options */ ); /* eslint-disable-line no-global-assign */ -const { History } = require('../../src/core/router/history/base'); const { expect } = require('chai'); +const { History } = require('../../src/core/router/history/base'); class MockHistory extends History { parse(path) { diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js index b1d95dfac..55ebe5e49 100644 --- a/test/unit/docsify.test.js +++ b/test/unit/docsify.test.js @@ -15,9 +15,6 @@ const markup = /* html */ `
- `; diff --git a/test/unit/render.test.js b/test/unit/render.test.js index 67d3bcf09..c3ed7b140 100644 --- a/test/unit/render.test.js +++ b/test/unit/render.test.js @@ -1,5 +1,5 @@ -const { init, expectSameDom } = require('../_helper'); const { expect } = require('chai'); +const { init, expectSameDom } = require('../_helper'); describe('render', function() { it('important content (tips)', async function() { diff --git a/test/unit/util.test.js b/test/unit/util.test.js index e4e8a0e3b..9dadf28a3 100644 --- a/test/unit/util.test.js +++ b/test/unit/util.test.js @@ -2,8 +2,8 @@ require = require('esm')( module /* , options */ ); /* eslint-disable-line no-global-assign */ -const { resolvePath } = require('../../src/core/router/util'); const { expect } = require('chai'); +const { resolvePath } = require('../../src/core/router/util'); describe('router/util', function() { it('resolvePath', async function() { From dca22f3ced04bd8e1dc9b1adbac6d96b230913cd Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 11:27:38 -0700 Subject: [PATCH 09/14] simplify import --- src/core/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/index.js b/src/core/index.js index 344bafdba..6e6164186 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,8 +1,8 @@ -import * as dom from './util/dom'; +import { documentReady } from './util/dom'; import { Docsify } from './Docsify'; /** * Run Docsify */ // eslint-disable-next-line no-unused-vars -dom.documentReady(_ => new Docsify()); +documentReady(_ => new Docsify()); From 41dc2c7d106e655e86bfd2f96a81167348d389ed Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 11:59:52 -0700 Subject: [PATCH 10/14] ensure that the test script runs a prod build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02fd700bd..1a90a84f4 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "dev:ssr": "run-p serve:ssr watch:*", "lint": "eslint .", "fixlint": "eslint . --fix", - "test": "mocha ./test/**/*.test.js", + "test": "npm run build && mocha ./test/**/*.test.js", "testServer": "node cypress/setup.js", "test:e2e": "start-server-and-test testServer http://localhost:3000 cy:run", "posttest:e2e": "rimraf cypress/fixtures/docs", From 31f1a645ee29d86044e72c5730ff0edae8484a0c Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 12:12:33 -0700 Subject: [PATCH 11/14] update outdated comment --- test/unit/docsify.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js index 55ebe5e49..5f38cab63 100644 --- a/test/unit/docsify.test.js +++ b/test/unit/docsify.test.js @@ -55,7 +55,8 @@ describe('Docsify public API', () => { const { documentReady } = require('../../src/core/util/dom'); await new Promise(resolve => documentReady(resolve, DOM.window.document)); - // deprecated global API, still works for now, backwards comaptible + // If the script was built successfully for production, then it should load + // and the following APIs should be available: expect(typeof DOM.window.Docsify).to.equal('object'); expect(typeof DOM.window.Docsify.util).to.equal('object'); expect(typeof DOM.window.Docsify.dom).to.equal('object'); From 63f1b88a41cf67202c3a2898b677756a4a079fd1 Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Sun, 7 Jun 2020 13:24:47 -0700 Subject: [PATCH 12/14] Revert "ensure that the test script runs a prod build" This reverts commit 41dc2c7d106e655e86bfd2f96a81167348d389ed because the GitHub Action (unit.yml) already run `npm run build`. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a90a84f4..02fd700bd 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "dev:ssr": "run-p serve:ssr watch:*", "lint": "eslint .", "fixlint": "eslint . --fix", - "test": "npm run build && mocha ./test/**/*.test.js", + "test": "mocha ./test/**/*.test.js", "testServer": "node cypress/setup.js", "test:e2e": "start-server-and-test testServer http://localhost:3000 cy:run", "posttest:e2e": "rimraf cypress/fixtures/docs", From 64a231d9247525c85fbd2ae85a256f47095e1ddb Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Wed, 10 Jun 2020 11:48:21 -0700 Subject: [PATCH 13/14] use a port for the tests that doesn't collide with common local server ports --- test/unit/docsify.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit/docsify.test.js b/test/unit/docsify.test.js index 5f38cab63..8f095c849 100644 --- a/test/unit/docsify.test.js +++ b/test/unit/docsify.test.js @@ -7,7 +7,8 @@ const handler = require('serve-handler'); const { expect } = require('chai'); const { initJSDOM } = require('../_helper'); -const docsifySite = 'http://127.0.0.1:3000'; +const port = 9753; +const docsifySite = 'http://127.0.0.1:' + port; const markup = /* html */ ` @@ -30,7 +31,7 @@ describe('Docsify public API', () => { return handler(request, response); }); - await new Promise(r => server.listen(3000, r)); + await new Promise(r => server.listen(port, r)); }); after(async () => { From 146e4c4e1834eae5815e6004083478ac4bb7e6df Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Fri, 12 Jun 2020 22:16:24 -0700 Subject: [PATCH 14/14] Update build/css.js Co-authored-by: James George --- build/css.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/css.js b/build/css.js index 3ae9701fe..2214f3fe4 100644 --- a/build/css.js +++ b/build/css.js @@ -36,13 +36,12 @@ fs.readdir(path.join(__dirname, '../src/themes'), (err, files) => { if (code !== 0) { console.error(message); process.exit(code) - } else { - console.log(message); } + console.log(message); }); } else { return } }) -}) \ No newline at end of file +})