From d6ecead32706c8d656e5f69fe33148df7e48db1f Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 27 Jul 2018 15:40:25 +0800 Subject: [PATCH 001/135] first commit --- .gitignore | 7 +++++++ README.md | 1 + package.json | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..b4f5aba992 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.vscode +.idea +.eslintcache +node_modules +dist + diff --git a/README.md b/README.md new file mode 100644 index 0000000000..2b497c97b0 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# blogi diff --git a/package.json b/package.json new file mode 100644 index 0000000000..9f037d77ee --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "blogi", + "version": "1.0.0", + "description": "Blog instantly", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/endiliey/blogi.git" + }, + "keywords": [ + "blog", + "websites", + "open source" + ], + "author": "endiliey", + "license": "MIT", + "bugs": { + "url": "https://github.com/endiliey/blogi/issues" + }, + "homepage": "https://github.com/endiliey/blogi#readme" +} From 06faff3474d6cb078ec1eee808309de2d6927ec3 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 27 Jul 2018 17:40:37 +0800 Subject: [PATCH 002/135] setup infra --- .eslintrc.js | 18 + .prettierrc | 8 + bin/blogi.js | 58 +++ blog/hello-world.md | 12 + lib/build.js | 4 + lib/dev.js | 3 + lib/index.js | 2 + package.json | 32 +- yarn.lock | 1211 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1344 insertions(+), 4 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .prettierrc create mode 100644 bin/blogi.js create mode 100644 blog/hello-world.md create mode 100644 lib/build.js create mode 100644 lib/dev.js create mode 100644 lib/index.js create mode 100644 yarn.lock diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..25293f3037 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +const OFF = 0; +const WARNING = 1; +const ERROR = 2; + +module.exports = { + env: { + browser: true, + commonjs: true, + jest: true, + node: true, + }, + extends: ['airbnb', 'prettier'], + rules: { + 'no-console': OFF, + 'func-names': OFF, + 'react/jsx-filename-extension': OFF, // Enable in future when migrating. + }, +}; \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..61480c22e5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "bracketSpacing": false, + "jsxBracketSameLine": true, + "parser": "flow", + "printWidth": 80, + "proseWrap": "never", + "singleQuote": true + } \ No newline at end of file diff --git a/bin/blogi.js b/bin/blogi.js new file mode 100644 index 0000000000..c9fd9746ac --- /dev/null +++ b/bin/blogi.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node + +const chalk = require('chalk'); +const semver = require('semver'); +const path = require('path'); +const program = require('commander'); +const {dev, build} = require('../lib'); +const requiredVersion = require('../package.json').engines.node; + +if (!semver.satisfies(process.version, requiredVersion)) { + console.log( + chalk.red(`\nMinimum node version not met :)`) + + chalk.yellow( + `\nYou are using Node ${ + process.version + }, but blogi requires Node ${requiredVersion}.\n` + ) + ); + process.exit(1); +} + +function wrapCommand(fn) { + return (...args) => + fn(...args).catch(err => { + console.error(chalk.red(err.stack)); + process.exitCode = 1; + }); +} + +program + .version(require('../package.json').version) + .usage(' [options]'); + +program + .command('dev [targetDir]') + .description('start development server') + .option('-p, --port ', 'use specified port (default: 8080)') + .action((dir = '.', {port}) => { + wrapCommand(dev)(path.resolve(dir), {port}); + }); + +program + .command('build [targetDir]') + .description('build dir as static site') + .option( + '-d, --dest ', + 'specify build output dir (default: .blogi/dist)' + ) + .action((dir = '.', {dest}) => { + const outDir = dest ? path.resolve(dest) : null; + wrapCommand(build)(path.resolve(dir), {outDir}); + }); + +program.parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp(); +} diff --git a/blog/hello-world.md b/blog/hello-world.md new file mode 100644 index 0000000000..13d9ddfec8 --- /dev/null +++ b/blog/hello-world.md @@ -0,0 +1,12 @@ +--- +title: Hello, World ! +author: Endilie Yacop Sucipto +authorURL: http://twitter.com/endiliey +authorFBID: 100000251103620 +--- + +Hi, Endilie here. + + + +Random thoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. diff --git a/lib/build.js b/lib/build.js new file mode 100644 index 0000000000..5b1054a533 --- /dev/null +++ b/lib/build.js @@ -0,0 +1,4 @@ +module.exports = async function build(sourceDir, cliOptions = {}) { + process.env.NODE_ENV = 'production'; + console.log('Build'); +}; diff --git a/lib/dev.js b/lib/dev.js new file mode 100644 index 0000000000..393be03951 --- /dev/null +++ b/lib/dev.js @@ -0,0 +1,3 @@ +module.exports = async function dev(sourceDir, cliOptions = {}) { + console.log('Development'); +}; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000000..689d88721c --- /dev/null +++ b/lib/index.js @@ -0,0 +1,2 @@ +exports.dev = require('./dev'); +exports.build = require('./build'); diff --git a/package.json b/package.json index 9f037d77ee..510b5b6404 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,15 @@ "name": "blogi", "version": "1.0.0", "description": "Blog instantly", - "main": "index.js", + "main": "lib/index.js", + "bin": { + "blogi": "bin/blogi.js" + }, "scripts": { + "dev": "node bin/blogi dev blog", + "build": "node bin/blogi build blog", + "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\"", + "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\"", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -12,13 +19,30 @@ }, "keywords": [ "blog", - "websites", - "open source" + "generator", + "react" ], "author": "endiliey", "license": "MIT", "bugs": { "url": "https://github.com/endiliey/blogi/issues" }, - "homepage": "https://github.com/endiliey/blogi#readme" + "homepage": "https://github.com/endiliey/blogi#readme", + "devDependencies": { + "eslint": "^4.19.1", + "eslint-config-airbnb": "17.0.0", + "eslint-config-prettier": "^2.9.0", + "eslint-plugin-import": "^2.12.0", + "eslint-plugin-jsx-a11y": "^6.0.3", + "eslint-plugin-react": "^7.9.1", + "prettier": "^1.13.7" + }, + "dependencies": { + "chalk": "^2.4.1", + "commander": "^2.16.0", + "semver": "^5.5.0" + }, + "engines": { + "node": ">=8" + } } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..1249a7289f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1211 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + +axobject-query@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.1.tgz#05dfa705ada8ad9db993fa6896f22d395b0b0a07" + dependencies: + ast-types-flow "0.0.7" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-from@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +color-convert@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +commander@^2.11.0, commander@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +damerau-levenshtein@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" + +debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +emoji-regex@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.6.1, es-abstract@^1.7.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +eslint-config-airbnb-base@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.0.0.tgz#2ee6279c4891128e49d6445b24aa13c2d1a21450" + dependencies: + eslint-restricted-globals "^0.1.1" + object.assign "^4.1.0" + object.entries "^1.0.4" + +eslint-config-airbnb@17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.0.0.tgz#1bb8c4255483320bb68c3b614f71ae6058b0b2db" + dependencies: + eslint-config-airbnb-base "^13.0.0" + object.assign "^4.1.0" + object.entries "^1.0.4" + +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + dependencies: + get-stdin "^5.0.1" + +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.12.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz#df24f241175e312d91662dc91ca84064caec14ed" + dependencies: + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.2.0" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + resolve "^1.6.0" + +eslint-plugin-jsx-a11y@^6.0.3: + version "6.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz#7bf56dbe7d47d811d14dbb3ddff644aa656ce8e1" + dependencies: + aria-query "^3.0.0" + array-includes "^3.0.3" + ast-types-flow "^0.0.7" + axobject-query "^2.0.1" + damerau-levenshtein "^1.0.4" + emoji-regex "^6.5.1" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + +eslint-plugin-react@^7.9.1: + version "7.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.10.0.tgz#af5c1fef31c4704db02098f9be18202993828b50" + dependencies: + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" + +eslint-restricted-globals@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + +eslint-scope@^3.7.1: + version "3.7.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +esquery@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.0.1: + version "11.7.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +hosted-git-info@^2.1.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + +iconv-lite@^0.4.17: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^3.3.3: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.9.1: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.17.4, lodash@^4.3.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +loose-envify@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^4.0.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-keys@^1.0.11, object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prettier@^1.13.7: + version "1.13.7" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@^1.5.0, resolve@^1.6.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +rimraf@^2.2.8: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +validate-npm-package-license@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" From 94c45e36cbb43821854a2d60daf8bc4b4000b40b Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 28 Jul 2018 16:06:07 +0800 Subject: [PATCH 003/135] feat: add siteConfig loader --- .gitignore | 2 +- lib/loader/blog.js | 0 lib/loader/config.js | 14 + lib/loader/index.js | 12 + package.json | 25 +- .../__fixtures__/custom/.blogi/config.js | 6 + test/loader/__fixtures__/custom/hello.md | 5 + .../__fixtures__/simple/.blogi/config.js | 4 + test/loader/__fixtures__/simple/hello.md | 5 + test/loader/config.test.js | 28 + yarn.lock | 4676 ++++++++++++++++- 11 files changed, 4726 insertions(+), 51 deletions(-) create mode 100644 lib/loader/blog.js create mode 100644 lib/loader/config.js create mode 100644 lib/loader/index.js create mode 100644 test/loader/__fixtures__/custom/.blogi/config.js create mode 100644 test/loader/__fixtures__/custom/hello.md create mode 100644 test/loader/__fixtures__/simple/.blogi/config.js create mode 100644 test/loader/__fixtures__/simple/hello.md create mode 100644 test/loader/config.test.js diff --git a/.gitignore b/.gitignore index b4f5aba992..c47a0349c6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ .eslintcache node_modules dist - +yarn-error.log diff --git a/lib/loader/blog.js b/lib/loader/blog.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/loader/config.js b/lib/loader/config.js new file mode 100644 index 0000000000..78ce9260d3 --- /dev/null +++ b/lib/loader/config.js @@ -0,0 +1,14 @@ +const fs = require('fs-extra'); +const path = require('path'); + +module.exports = function loadConfig(sourceDir, deleteCache = true) { + const configPath = path.resolve(sourceDir, '.blogi', 'config.js'); + if (deleteCache) { + delete require.cache[configPath]; + } + let config = {}; + if (fs.existsSync(configPath)) { + config = require(configPath); + } + return config; +}; diff --git a/lib/loader/index.js b/lib/loader/index.js new file mode 100644 index 0000000000..7df5836cd9 --- /dev/null +++ b/lib/loader/index.js @@ -0,0 +1,12 @@ +const path = require('path'); +const loadConfig = require('./config'); + +module.exports = async function load(sourceDir) { + // 1. load siteConfig + const siteConfig = loadConfig(sourceDir); + + // 2. extract metadata from markdown files + const metadatas = []; + + return null; // todo +}; diff --git a/package.json b/package.json index 510b5b6404..b22a1b204c 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,9 @@ "scripts": { "dev": "node bin/blogi dev blog", "build": "node bin/blogi build blog", - "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\"", - "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\"", - "test": "echo \"Error: no test specified\" && exit 1" + "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", + "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", + "test": "jest" }, "repository": { "type": "git", @@ -35,14 +35,31 @@ "eslint-plugin-import": "^2.12.0", "eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-react": "^7.9.1", + "jest": "^23.4.2", "prettier": "^1.13.7" }, "dependencies": { "chalk": "^2.4.1", + "chokidar": "^2.0.4", "commander": "^2.16.0", - "semver": "^5.5.0" + "connect-history-api-fallback": "^1.5.0", + "fs-extra": "^7.0.0", + "koa-connect": "^2.0.1", + "koa-convert": "^1.2.0", + "koa-mount": "^3.0.0", + "koa-range": "^0.3.0", + "koa-static": "^5.0.0", + "ora": "^3.0.0", + "semver": "^5.5.0", + "webpack": "^4.16.3", + "webpack-chain": "^4.8.0", + "webpack-serve": "^2.0.2" }, "engines": { "node": ">=8" + }, + "jest": { + "testPathIgnorePatterns": ["/node_modules/", "__fixtures__"], + "testEnvironment": "node" } } diff --git a/test/loader/__fixtures__/custom/.blogi/config.js b/test/loader/__fixtures__/custom/.blogi/config.js new file mode 100644 index 0000000000..8897ce391c --- /dev/null +++ b/test/loader/__fixtures__/custom/.blogi/config.js @@ -0,0 +1,6 @@ +module.exports = { + title: 'Hello World', + description: 'Hello World', + dest: 'blogi', + base: 'blogi' +}; diff --git a/test/loader/__fixtures__/custom/hello.md b/test/loader/__fixtures__/custom/hello.md new file mode 100644 index 0000000000..b846caae80 --- /dev/null +++ b/test/loader/__fixtures__/custom/hello.md @@ -0,0 +1,5 @@ +--- +title: Hello, World ! +--- + +Hello World diff --git a/test/loader/__fixtures__/simple/.blogi/config.js b/test/loader/__fixtures__/simple/.blogi/config.js new file mode 100644 index 0000000000..14da102249 --- /dev/null +++ b/test/loader/__fixtures__/simple/.blogi/config.js @@ -0,0 +1,4 @@ +module.exports = { + title: 'Hello World', + description: 'Hello World' +}; diff --git a/test/loader/__fixtures__/simple/hello.md b/test/loader/__fixtures__/simple/hello.md new file mode 100644 index 0000000000..b846caae80 --- /dev/null +++ b/test/loader/__fixtures__/simple/hello.md @@ -0,0 +1,5 @@ +--- +title: Hello, World ! +--- + +Hello World diff --git a/test/loader/config.test.js b/test/loader/config.test.js new file mode 100644 index 0000000000..c4aab7892b --- /dev/null +++ b/test/loader/config.test.js @@ -0,0 +1,28 @@ +const path = require('path'); +const fs = require('fs'); +const loadConfig = require('../../lib/loader/config'); + +describe('loadConfig', () => { + const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); + const customDir = path.join(__dirname, '__fixtures__', 'custom'); + + test('simple', () => { + expect(loadConfig(simpleDir)).toMatchInlineSnapshot(` +Object { + "description": "Hello World", + "title": "Hello World", +} +`); + }); + + test('custom', () => { + expect(loadConfig(customDir)).toMatchInlineSnapshot(` +Object { + "base": "blogi", + "description": "Hello World", + "dest": "blogi", + "title": "Hello World", +} +`); + }); +}); diff --git a/yarn.lock b/yarn.lock index 1249a7289f..24dff61014 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,246 @@ # yarn lockfile v1 +"@babel/code-frame@^7.0.0-beta.35": + version "7.0.0-beta.54" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.54.tgz#0024f96fdf7028a21d68e273afd4e953214a1ead" + dependencies: + "@babel/highlight" "7.0.0-beta.54" + +"@babel/highlight@7.0.0-beta.54": + version "7.0.0-beta.54" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.54.tgz#155d507358329b8e7068970017c3fd74a9b08584" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@shellscape/koa-send@^4.1.0": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@shellscape/koa-send/-/koa-send-4.1.3.tgz#1a7c8df21f63487e060b7bfd8ed82e1d3c4ae0b0" + dependencies: + debug "^2.6.3" + http-errors "^1.6.1" + mz "^2.6.0" + resolve-path "^1.3.3" + +"@shellscape/koa-static@^4.0.4": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@shellscape/koa-static/-/koa-static-4.0.5.tgz#b329b55bfd41056a6981c584ae6bace30b5b6b3b" + dependencies: + "@shellscape/koa-send" "^4.1.0" + debug "^2.6.8" + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + +"@webassemblyjs/ast@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25" + dependencies: + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" + debug "^3.1.0" + mamacro "^0.0.3" + +"@webassemblyjs/floating-point-hex-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298" + +"@webassemblyjs/helper-api-error@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59" + +"@webassemblyjs/helper-buffer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e" + dependencies: + debug "^3.1.0" + +"@webassemblyjs/helper-code-frame@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58" + dependencies: + "@webassemblyjs/wast-printer" "1.5.13" + +"@webassemblyjs/helper-fsm@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924" + +"@webassemblyjs/helper-module-context@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5" + dependencies: + debug "^3.1.0" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747" + +"@webassemblyjs/helper-wasm-section@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/ieee754@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364" + dependencies: + ieee754 "^1.1.11" + +"@webassemblyjs/leb128@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee" + dependencies: + long "4.0.0" + +"@webassemblyjs/utf8@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469" + +"@webassemblyjs/wasm-edit@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/helper-wasm-section" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + "@webassemblyjs/wast-printer" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/wasm-gen@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wasm-opt@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/wasm-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wast-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/floating-point-hex-parser" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-code-frame" "1.5.13" + "@webassemblyjs/helper-fsm" "1.5.13" + long "^3.2.0" + mamacro "^0.0.3" + +"@webassemblyjs/wast-printer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" + long "^3.2.0" + +"@webpack-contrib/cli-utils@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@webpack-contrib/cli-utils/-/cli-utils-1.0.2.tgz#9618b68a79f5b3462224e0ecca416cc812b65054" + dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + camelize "^1.0.0" + chalk "^2.4.1" + decamelize "^2.0.0" + loader-utils "^1.1.0" + meant "^1.0.1" + strip-ansi "^4.0.0" + text-table "^0.2.0" + webpack-log "^1.2.0" + +"@webpack-contrib/config-loader@^1.1.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@webpack-contrib/config-loader/-/config-loader-1.2.1.tgz#5b3dd474e207437939d294d200c68b7b00008e04" + dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + chalk "^2.1.0" + cosmiconfig "^5.0.2" + is-plain-obj "^1.1.0" + loud-rejection "^1.6.0" + merge-options "^1.0.1" + minimist "^1.2.0" + resolve "^1.6.0" + webpack-log "^1.1.2" + +"@webpack-contrib/schema-utils@^1.0.0-beta.0": + version "1.0.0-beta.0" + resolved "https://registry.yarnpkg.com/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chalk "^2.3.2" + strip-ansi "^4.0.0" + text-table "^0.2.0" + webpack-log "^1.1.2" + +abab@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" + +abab@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accepts@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + +acorn-globals@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" + dependencies: + acorn "^5.0.0" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -12,7 +252,7 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.5.0: +acorn@^5.0.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -20,7 +260,11 @@ ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" -ajv@^5.2.3, ajv@^5.3.0: +ajv-keywords@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + +ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -29,6 +273,33 @@ ajv@^5.2.3, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.1.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.0" + ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" @@ -45,12 +316,48 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: color-convert "^1.9.0" +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +app-root-path@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" + +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + dependencies: + default-require-extensions "^2.0.0" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +arch@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -64,6 +371,32 @@ aria-query@^3.0.0: ast-types-flow "0.0.7" commander "^2.11.0" +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + array-includes@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" @@ -81,21 +414,93 @@ array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" -arrify@^1.0.0: +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + ast-types-flow@0.0.7, ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +async@^1.4.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.1.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + axobject-query@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.1.tgz#05dfa705ada8ad9db993fa6896f22d395b0b0a07" dependencies: ast-types-flow "0.0.7" -babel-code-frame@^6.22.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -103,10 +508,197 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" +babel-core@^6.0.0, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.18.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-jest@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-23.4.2.tgz#f276de67798a5d68f2d6e87ff518c2f6e1609877" + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.2.0" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + +babel-plugin-jest-hoist@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" + +babel-plugin-syntax-object-rest-spread@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-preset-jest@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" + dependencies: + babel-plugin-jest-hoist "^23.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +bluebird@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -114,14 +706,165 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-process-hrtime@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" + +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + dependencies: + resolve "1.1.7" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cache-content-type@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" + dependencies: + mime-types "^2.1.18" + ylru "^1.2.0" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -132,6 +875,51 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +camelcase-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" + dependencies: + camelcase "^4.1.0" + map-obj "^2.0.0" + quick-lru "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^4.0.0, camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + dependencies: + rsvp "^3.3.3" + +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -142,7 +930,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: @@ -154,24 +942,119 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +chokidar@^2.0.2, chokidar@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + dependencies: + tslib "^1.9.0" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" +cli-spinners@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" +clipboardy@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef" + dependencies: + arch "^2.1.0" + execa "^0.8.0" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: version "1.9.2" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" @@ -182,15 +1065,37 @@ color-name@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" +combined-stream@1.0.6, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + commander@^2.11.0, commander@^2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +compare-versions@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.3.0.tgz#af93ea705a96943f622ab309578b9b90586f39c3" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -199,15 +1104,124 @@ concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +connect-history-api-fallback@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -core-util-is@~1.0.0: +content-disposition@~0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^1.4.0, convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +cookies@~0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" + dependencies: + depd "~1.1.1" + keygrip "~1.0.2" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.1.0: +cosmiconfig@^5.0.2: + version "5.0.5" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -215,11 +1229,75 @@ cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" + +cssstyle@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.0.0.tgz#79b16d51ec5591faec60e688891f15d2a5705129" + dependencies: + cssom "0.3.x" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + damerau-levenshtein@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" -debug@^2.6.8, debug@^2.6.9: +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.0.0.tgz#24802de4e81c298ea8a9388bb0d8e461c774684f" + dependencies: + abab "^1.0.4" + whatwg-mimetype "^2.0.0" + whatwg-url "^6.4.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1, debug@^2.6.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -231,10 +1309,55 @@ debug@^3.1.0: dependencies: ms "2.0.0" +decamelize-keys@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + dependencies: + xregexp "4.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +deepmerge@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" + +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + dependencies: + strip-bom "^3.0.0" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -242,6 +1365,25 @@ define-properties@^1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -254,6 +1396,55 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@^1.1.2, depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +diff@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -267,17 +1458,96 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + dependencies: + webidl-conversions "^4.0.2" + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + emoji-regex@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" -error-ex@^1.2.0: +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" -es-abstract@^1.6.1, es-abstract@^1.7.0: +error-inject@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + +es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: @@ -295,10 +1565,48 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" +es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.45" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "1" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escodegen@^1.9.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-airbnb-base@^13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.0.0.tgz#2ee6279c4891128e49d6445b24aa13c2d1a21450" @@ -383,6 +1691,13 @@ eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" @@ -437,6 +1752,10 @@ espree@^3.5.4: acorn "^5.5.0" acorn-jsx "^3.0.0" +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -453,7 +1772,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -461,6 +1780,103 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + dependencies: + merge "^1.2.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expect@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-23.4.0.tgz#6da4ecc99c1471253e7288338983ad1ebadb60c3" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.2.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.2.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + external-editor@^2.0.4: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" @@ -469,10 +1885,41 @@ external-editor@^2.0.4: iconv-lite "^0.4.17" tmp "^0.0.33" +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -481,6 +1928,12 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + dependencies: + bser "^2.0.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -494,6 +1947,44 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -501,7 +1992,7 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.0.0: +find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: @@ -516,14 +2007,90 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@~0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" +fsevents@^1.2.2, fsevents@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + function-bind@^1.1.0, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -532,11 +2099,66 @@ functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-port@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + get-stdin@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -547,10 +2169,20 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + dependencies: + ini "^1.3.4" + globals@^11.0.1: version "11.7.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -562,16 +2194,61 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2: +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.3: + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -580,30 +2257,161 @@ has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" -iconv-lite@^0.4.17: +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + dependencies: + whatwg-encoding "^1.0.1" + +http-assert@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" + dependencies: + deep-equal "~1.0.1" + http-errors "~1.6.1" + +http-errors@^1.6.1, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +iconv-lite@^0.4.17, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.11, ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + ignore@^3.3.3: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -611,10 +2419,18 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" @@ -634,10 +2450,42 @@ inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" @@ -648,14 +2496,149 @@ is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -672,10 +2655,32 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-plain-obj@^1.1, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -686,11 +2691,35 @@ is-resolvable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" -isarray@^1.0.0, isarray@~1.0.0: +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -698,35 +2727,630 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul-api@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.1.tgz#4c3b05d18c0016d1022e079b98dc82c40f488954" + dependencies: + async "^2.1.4" + compare-versions "^3.1.0" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-hook "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-report "^1.1.4" + istanbul-lib-source-maps "^1.2.4" + istanbul-reports "^1.3.0" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" + +istanbul-lib-hook@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz#f614ec45287b2a8fc4f07f5660af787575601805" + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.0" + semver "^5.3.0" + +istanbul-lib-report@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz#e886cdf505c4ebbd8e099e4396a90d0a28e2acb5" + dependencies: + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz#ffe6be4e7ab86d3603e4290d54990b14506fc9b1" + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.3.0.tgz#2f322e81e1d9520767597dca3c20a0cce89a3554" + dependencies: + handlebars "^4.0.3" + +javascript-stringify@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3" + +jest-changed-files@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" + dependencies: + throat "^4.0.0" + +jest-cli@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.4.2.tgz#49d56bcfe6cf01871bfcc4a0494e08edaf2b61d0" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.4.2" + jest-config "^23.4.2" + jest-environment-jsdom "^23.4.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.4.1" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve-dependencies "^23.4.2" + jest-runner "^23.4.2" + jest-runtime "^23.4.2" + jest-snapshot "^23.4.2" + jest-util "^23.4.0" + jest-validate "^23.4.0" + jest-watcher "^23.4.0" + jest-worker "^23.2.0" + micromatch "^2.3.11" + node-notifier "^5.2.1" + prompts "^0.1.9" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + +jest-config@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.4.2.tgz#62a105e14b8266458f2bf4d32403b2c44418fa77" + dependencies: + babel-core "^6.0.0" + babel-jest "^23.4.2" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.4.0" + jest-environment-node "^23.4.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.4.2" + jest-regex-util "^23.3.0" + jest-resolve "^23.4.1" + jest-util "^23.4.0" + jest-validate "^23.4.0" + pretty-format "^23.2.0" + +jest-diff@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.2.0.tgz#9f2cf4b51e12c791550200abc16b47130af1062a" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.2.0" + +jest-docblock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.4.0.tgz#2fa9edd89daa1a4edc9ff9bf6062a36b71345143" + dependencies: + chalk "^2.0.1" + pretty-format "^23.2.0" + +jest-environment-jsdom@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jsdom "^11.5.1" + +jest-environment-node@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + +jest-get-type@^22.1.0: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + +jest-haste-map@^23.4.1: + version "23.4.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.4.1.tgz#43a174ba7ac079ae1dd74eaf5a5fe78989474dd2" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^23.2.0" + jest-serializer "^23.0.1" + jest-worker "^23.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.4.2.tgz#2fbf52f93e43ed4c5e7326a90bb1d785be4321ac" + dependencies: + babel-traverse "^6.0.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^23.4.0" + is-generator-fn "^1.0.0" + jest-diff "^23.2.0" + jest-each "^23.4.0" + jest-matcher-utils "^23.2.0" + jest-message-util "^23.4.0" + jest-snapshot "^23.4.2" + jest-util "^23.4.0" + pretty-format "^23.2.0" + +jest-leak-detector@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.2.0.tgz#c289d961dc638f14357d4ef96e0431ecc1aa377d" + dependencies: + pretty-format "^23.2.0" + +jest-matcher-utils@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.2.0.tgz#4d4981f23213e939e3cedf23dc34c747b5ae1913" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.2.0" + +jest-message-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" + +jest-regex-util@^23.3.0: + version "23.3.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" + +jest-resolve-dependencies@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.4.2.tgz#0675ba876a5b819deffc449ad72e9985c2592048" + dependencies: + jest-regex-util "^23.3.0" + jest-snapshot "^23.4.2" + +jest-resolve@^23.4.1: + version "23.4.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.4.1.tgz#7f3c17104732a2c0c940a01256025ed745814982" + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.4.2.tgz#579a88524ac52c846075b0129a21c7b483e75a7e" + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.4.2" + jest-docblock "^23.2.0" + jest-haste-map "^23.4.1" + jest-jasmine2 "^23.4.2" + jest-leak-detector "^23.2.0" + jest-message-util "^23.4.0" + jest-runtime "^23.4.2" + jest-util "^23.4.0" + jest-worker "^23.2.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.4.2.tgz#00c3bb8385253d401a394a27d1112d3615e5a65c" + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.4.2" + jest-haste-map "^23.4.1" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.4.1" + jest-snapshot "^23.4.2" + jest-util "^23.4.0" + jest-validate "^23.4.0" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + +jest-snapshot@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.4.2.tgz#8fa6130feb5a527dac73e5fa80d86f29f7c42ab6" + dependencies: + babel-types "^6.0.0" + chalk "^2.0.1" + jest-diff "^23.2.0" + jest-matcher-utils "^23.2.0" + jest-message-util "^23.4.0" + jest-resolve "^23.4.1" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.2.0" + semver "^5.5.0" + +jest-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.4.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + +jest-validate@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.4.0.tgz#d96eede01ef03ac909c009e9c8e455197d48c201" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.2.0" + +jest-watcher@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + dependencies: + merge-stream "^1.0.1" + +jest@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-23.4.2.tgz#1fae3ed832192143070ae85156b25cea891a1260" + dependencies: + import-local "^1.0.0" + jest-cli "^23.4.2" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@^3.9.1: +js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + jsx-ast-utils@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" dependencies: array-includes "^3.0.3" +keygrip@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" + +killable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +kleur@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.1.tgz#7cc64b0d188d0dcbc98bdcdfdda2cc10619ddce8" + +koa-compose@^3.0.0, koa-compose@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + +koa-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/koa-connect/-/koa-connect-2.0.1.tgz#2acad159c33862de1d73aa4562a48de13f137c0f" + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa-mount@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" + dependencies: + debug "^2.6.1" + koa-compose "^3.2.1" + +koa-range@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac" + dependencies: + stream-slice "^0.1.2" + +koa-send@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" + dependencies: + debug "^3.1.0" + http-errors "^1.6.3" + mz "^2.7.0" + resolve-path "^1.4.0" + +koa-static@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" + dependencies: + debug "^3.1.0" + koa-send "^5.0.0" + +koa-webpack@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/koa-webpack/-/koa-webpack-5.1.0.tgz#7b9f04ea85c43c4d7ad845d0de01f0ed495eb5c0" + dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + app-root-path "^2.0.1" + loud-rejection "^1.6.0" + merge-options "^1.0.0" + webpack-dev-middleware "^3.0.0" + webpack-hot-client "^4.1.0" + webpack-log "^1.1.1" + +koa@^2.4.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.2.tgz#f2bda7f3e70be54924e7e5e9789a249f77256fe3" + dependencies: + accepts "^1.3.5" + cache-content-type "^1.0.0" + content-disposition "~0.5.2" + content-type "^1.0.4" + cookies "~0.7.1" + debug "^3.1.0" + delegates "^1.0.0" + depd "^1.1.2" + destroy "^1.0.4" + error-inject "^1.0.0" + escape-html "^1.0.3" + fresh "~0.5.2" + http-assert "^1.3.0" + http-errors "^1.6.3" + is-generator-function "^1.0.7" + koa-compose "^4.1.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + on-finished "^2.3.0" + only "~0.0.2" + parseurl "^1.3.2" + statuses "^1.5.0" + type-is "^1.6.16" + vary "^1.1.2" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -734,6 +3358,16 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -743,6 +3377,27 @@ load-json-file@^2.0.0: pify "^2.0.0" strip-bom "^3.0.0" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -750,43 +3405,316 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash@^4.17.4, lodash@^4.3.0: +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" -loose-envify@^1.3.1: +log-symbols@^2.1.0, log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +loglevelnext@^1.0.1, loglevelnext@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" + dependencies: + es6-symbol "^3.1.1" + object.assign "^4.1.0" + +long@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + +long@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru-cache@^4.0.1: +loud-rejection@^1.0.0, loud-rejection@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^4.0.1, lru-cache@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +map-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +meant@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +mem@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mem/-/mem-3.0.1.tgz#152410d0d7e835e4a4363e626238d9e5be3d6f5a" + dependencies: + mimic-fn "^1.0.0" + p-is-promise "^1.1.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + yargs-parser "^10.0.0" + +merge-options@^1.0.0, merge-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32" + dependencies: + is-plain-obj "^1.1" + +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + +merge@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + +mime@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" +minimist-options@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -mkdirp@^0.5.1: +minimist@^1.1.1, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -795,11 +3723,150 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +mz@^2.6.0, mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanoassert@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d" + +nanobus@^4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/nanobus/-/nanobus-4.3.3.tgz#a9635d38c687853641e2646bb2be6510cf966233" + dependencies: + nanotiming "^7.2.0" + remove-array-items "^1.0.0" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +nanoscheduler@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/nanoscheduler/-/nanoscheduler-1.0.3.tgz#6ca027941bf3e04139ea4bab6227ea6ad803692f" + dependencies: + nanoassert "^1.1.0" + +nanotiming@^7.2.0: + version "7.3.1" + resolved "https://registry.yarnpkg.com/nanotiming/-/nanotiming-7.3.1.tgz#dc5cf8d9d8ad401a4394d1a9b7a16714bccfefda" + dependencies: + nanoassert "^1.1.0" + nanoscheduler "^1.0.2" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -normalize-package-data@^2.3.2: +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +neo-async@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" + +next-tick@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-notifier@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + dependencies: + growly "^1.3.0" + semver "^5.4.1" + shellwords "^0.1.1" + which "^1.3.0" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-version@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/node-version/-/node-version-1.2.0.tgz#34fde3ffa8e1149bd323983479dda620e1b5060d" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -808,14 +3875,72 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -object-assign@^4.0.1, object-assign@^4.1.1: +normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.11" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +nwsapi@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.7.tgz#6fc54c254621f10cac5225b76e81c74120139b78" + +oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + object-keys@^1.0.11, object-keys@^1.0.8: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" @@ -834,7 +3959,33 @@ object.entries@^1.0.4: function-bind "^1.1.0" has "^1.0.1" -once@^1.3.0: +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +on-finished@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -846,7 +3997,24 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -optionator@^0.8.2: +only@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + +opn@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + dependencies: + is-wsl "^1.1.0" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -857,10 +4025,56 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -os-tmpdir@~1.0.2: +ora@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.0.0.tgz#8179e3525b9aafd99242d63cc206fd64732741d0" + dependencies: + chalk "^2.3.1" + cli-cursor "^2.1.0" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -873,16 +4087,94 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + +p-series@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-series/-/p-series-1.1.0.tgz#f2d8522cdfd58b464eb9685651d465037ee3c957" + dependencies: + "@sindresorhus/is" "^0.7.0" + p-reduce "^1.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +parseurl@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -893,7 +4185,7 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" -path-is-absolute@^1.0.0: +path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -901,20 +4193,56 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" dependencies: pify "^2.0.0" +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + dependencies: + pify "^3.0.0" + +pbkdf2@^3.0.3: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -931,26 +4259,74 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + prettier@^1.13.7: version "1.13.7" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" +pretty-format@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.2.0.tgz#3b0aaa63c018a53583373c1cb3a5d96cc5e83017" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +prompts@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.13.tgz#7fad7ee1c6cafe49834ca0b2a6a471262de57620" + dependencies: + kleur "^2.0.1" + sisteransi "^0.1.1" + prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" @@ -958,10 +4334,112 @@ prop-types@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" +psl@^1.1.24: + version "1.1.28" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quick-lru@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" + +randomatic@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -969,6 +4447,21 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -977,7 +4470,15 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.2.2: +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -989,10 +4490,131 @@ readable-stream@^2.2.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +realpath-native@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.1.tgz#07f40a0cce8f8261e2e8b7ebebf5c95965d7b633" + dependencies: + util.promisify "^1.0.0" + +redent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" + dependencies: + indent-string "^3.0.0" + strip-indent "^2.0.0" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexpp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +registry-auth-token@^3.0.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +remove-array-items@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/remove-array-items/-/remove-array-items-1.0.0.tgz#07bf42cb332f4cf6e85ead83b5e4e896d2326b21" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@^2.87.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.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.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -1000,10 +4622,35 @@ require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-path@^1.3.3, resolve-path@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + dependencies: + http-errors "~1.6.2" + path-is-absolute "1.0.1" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + resolve@^1.5.0, resolve@^1.6.0: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" @@ -1017,18 +4664,45 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" -rimraf@^2.2.8: +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + rx-lite-aggregates@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" @@ -1039,18 +4713,101 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" -"safer-buffer@>= 2.1.2 < 3": +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: +sane@^2.0.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +schema-utils@^0.4.4, schema-utils@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +serialize-javascript@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -1061,16 +4818,100 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -signal-exit@^3.0.2: +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +sisteransi@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" dependencies: is-fullwidth-code-point "^2.0.0" +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + spdx-correct@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" @@ -1093,24 +4934,117 @@ spdx-license-ids@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" -string-width@^2.1.0, string-width@^2.1.1: +sshpk@^1.7.0: + version "1.14.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + safer-buffer "^2.0.2" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +stack-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", statuses@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +stream-slice@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@~1.1.1: +string_decoder@^1.0.0, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0: +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -1122,10 +5056,24 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-bom@^3.0.0: +strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -1134,12 +5082,22 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + supports-color@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" +symbol-tree@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" @@ -1151,34 +5109,341 @@ table@4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" -text-table@~0.2.0: +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" + +tar@^4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + +test-exclude@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.1.tgz#dfa222f03480bca69207ca728b37d74b45f724fa" + dependencies: + arrify "^1.0.1" + micromatch "^3.1.8" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + dependencies: + any-promise "^1.0.0" + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +time-fix-plugin@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/time-fix-plugin/-/time-fix-plugin-2.0.3.tgz#b6b1ead519099bc621e28edb77dac7531918b7e1" + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: os-tmpdir "~1.0.2" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@>=2.3.3, tough-cookie@^2.3.4: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + dependencies: + punycode "^2.1.0" + +trim-newlines@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" +type-is@^1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +uglify-js@^2.6: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uglifyjs-webpack-plugin@^1.2.4: + version "1.2.7" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz#57638dd99c853a1ebfe9d97b42160a8a507f9d00" + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +update-notifier@^2.3.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +uri-js@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-join@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + +uuid@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +v8-compile-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" + validate-npm-package-license@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" @@ -1186,26 +5451,345 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -which@^1.2.9: +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + dependencies: + browser-process-hrtime "^0.1.2" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + +webpack-chain@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.8.0.tgz#06fc3dbb9f2707d4c9e899fc6250fbcf2afe6fd1" + dependencies: + deepmerge "^1.5.2" + javascript-stringify "^1.6.0" + +webpack-dev-middleware@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.1.3.tgz#8b32aa43da9ae79368c1bf1183f2b6cf5e1f39ed" + dependencies: + loud-rejection "^1.6.0" + memory-fs "~0.4.1" + mime "^2.1.0" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + url-join "^4.0.0" + webpack-log "^1.0.1" + +webpack-hot-client@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-hot-client/-/webpack-hot-client-4.1.1.tgz#fc02b396749d5fd26c4f2265567e2fc1521a41ff" + dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + json-stringify-safe "^5.0.1" + loglevelnext "^1.0.2" + merge-options "^1.0.1" + strip-ansi "^4.0.0" + uuid "^3.1.0" + webpack-log "^1.1.1" + ws "^4.0.0" + +webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" + dependencies: + chalk "^2.1.0" + log-symbols "^2.1.0" + loglevelnext "^1.0.1" + uuid "^3.1.0" + +webpack-serve@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/webpack-serve/-/webpack-serve-2.0.2.tgz#6263b7c2888e169f84105da2119079098512b404" + dependencies: + "@shellscape/koa-static" "^4.0.4" + "@webpack-contrib/cli-utils" "^1.0.2" + "@webpack-contrib/config-loader" "^1.1.1" + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + chalk "^2.3.0" + clipboardy "^1.2.2" + cosmiconfig "^5.0.2" + debug "^3.1.0" + decamelize "^2.0.0" + get-port "^3.2.0" + import-local "^1.0.0" + is-plain-obj "^1.1.0" + killable "^1.0.0" + koa "^2.4.1" + koa-webpack "^5.1.0" + loud-rejection "^1.6.0" + mem "^3.0.0" + meow "^5.0.0" + merge-options "^1.0.1" + nanobus "^4.3.1" + node-version "^1.1.3" + opn "^5.1.0" + p-defer "^1.0.0" + p-series "^1.1.0" + resolve "^1.6.0" + strip-ansi "^4.0.0" + time-fix-plugin "^2.0.0" + update-notifier "^2.3.0" + url-join "^4.0.0" + v8-compile-cache "^2.0.0" + webpack-log "^1.1.2" + +webpack-sources@^1.0.1, webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.16.3: + version "4.16.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/wasm-edit" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + acorn "^5.6.2" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.0.0" + uglifyjs-webpack-plugin "^1.2.4" + watchpack "^1.5.0" + webpack-sources "^1.0.1" + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" + dependencies: + iconv-lite "0.4.19" + +whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" + +whatwg-url@^6.4.0, whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.12, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" + dependencies: + string-width "^2.1.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +write-file-atomic@^2.0.0, write-file-atomic@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" +ws@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +ylru@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" From d2e12a8e613159c605776cef22b5ea7ca22a8730 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 28 Jul 2018 18:04:56 +0800 Subject: [PATCH 004/135] feat: add blog loader --- .babelrc | 10 + lib/loader/blog.js | 52 ++ lib/loader/index.js | 12 +- package.json | 8 +- test/loader/__fixtures__/custom/foo/bar.md | 6 + test/loader/__fixtures__/custom/foo/baz.md | 5 + test/loader/__fixtures__/custom/hello.md | 1 + test/loader/__fixtures__/simple/hello.md | 1 + test/loader/__snapshots__/blog.test.js.snap | 46 ++ test/loader/__snapshots__/config.test.js.snap | 17 + test/loader/blog.test.js | 18 + test/loader/config.test.js | 16 +- yarn.lock | 466 +++++++++++++++++- 13 files changed, 633 insertions(+), 25 deletions(-) create mode 100644 .babelrc create mode 100644 test/loader/__fixtures__/custom/foo/bar.md create mode 100644 test/loader/__fixtures__/custom/foo/baz.md create mode 100644 test/loader/__snapshots__/blog.test.js.snap create mode 100644 test/loader/__snapshots__/config.test.js.snap create mode 100644 test/loader/blog.test.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000000..3fea2ed8ac --- /dev/null +++ b/.babelrc @@ -0,0 +1,10 @@ +{ + "env": { + "test": { + "presets": [ + ["env", { "targets": { "node": 8 }}] + ] + } + } + } + \ No newline at end of file diff --git a/lib/loader/blog.js b/lib/loader/blog.js index e69de29bb2..c654e67096 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -0,0 +1,52 @@ +const fs = require('fs-extra'); +const path = require('path'); +const fm = require('front-matter'); +const globby = require('globby'); +const indexRE = /(^|.*\/)index\.md$/i; +const extRE = /\.md$/; + +function fileToPath(file) { + if (indexRE.test(file)) { + // index.md -> / + // foo/index.md -> /foo/ + return file.replace(indexRE, '/$1'); + } else { + // foo.md -> /foo.html + // foo/bar.md -> /foo/bar.html + return `/${file.replace(extRE, '').replace(/\\/g, '/')}.html`; + } +} + +function parse(fileString) { + if (!fm.test(fileString)) { + return {metadata: null, content: fileString}; + } + const {attributes: metadata, body: content} = fm(fileString); + + return {metadata, content}; +} + +async function loadBlog(sourceDir) { + const blogFiles = await globby(['**/*.md', '!.blogi', '!node_modules'], { + cwd: sourceDir + }); + + const blogDatas = await Promise.all( + blogFiles.map(async file => { + const filepath = path.resolve(sourceDir, file); + const fileString = await fs.readFile(filepath, 'utf-8'); + const {metadata, content} = parse(fileString); + + return { + path: fileToPath(file), + content: content, + title: metadata.title, + date: metadata.date + }; + }) + ); + blogDatas.sort((a, b) => b.date - a.date); + return blogDatas; +} + +module.exports = loadBlog; diff --git a/lib/loader/index.js b/lib/loader/index.js index 7df5836cd9..d983770936 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -1,12 +1,18 @@ const path = require('path'); const loadConfig = require('./config'); +const loadBlog = require('./blog'); module.exports = async function load(sourceDir) { // 1. load siteConfig const siteConfig = loadConfig(sourceDir); - // 2. extract metadata from markdown files - const metadatas = []; + // 2. extract data from all blog files + const blogDatas = await loadBlog(sourceDir); - return null; // todo + // 3. TODO + + return { + siteConfig, + blogDatas + }; }; diff --git a/package.json b/package.json index b22a1b204c..95e52a68b4 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "homepage": "https://github.com/endiliey/blogi#readme", "devDependencies": { + "babel-preset-env": "^1.7.0", "eslint": "^4.19.1", "eslint-config-airbnb": "17.0.0", "eslint-config-prettier": "^2.9.0", @@ -43,7 +44,9 @@ "chokidar": "^2.0.4", "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", + "front-matter": "^2.3.0", "fs-extra": "^7.0.0", + "globby": "^8.0.1", "koa-connect": "^2.0.1", "koa-convert": "^1.2.0", "koa-mount": "^3.0.0", @@ -59,7 +62,10 @@ "node": ">=8" }, "jest": { - "testPathIgnorePatterns": ["/node_modules/", "__fixtures__"], + "testPathIgnorePatterns": [ + "/node_modules/", + "__fixtures__" + ], "testEnvironment": "node" } } diff --git a/test/loader/__fixtures__/custom/foo/bar.md b/test/loader/__fixtures__/custom/foo/bar.md new file mode 100644 index 0000000000..ba294597fd --- /dev/null +++ b/test/loader/__fixtures__/custom/foo/bar.md @@ -0,0 +1,6 @@ +--- +title: Lorem ipsum +date: 2018-06-20 +--- + +Lorem ipsum diff --git a/test/loader/__fixtures__/custom/foo/baz.md b/test/loader/__fixtures__/custom/foo/baz.md new file mode 100644 index 0000000000..c4e0cbf40d --- /dev/null +++ b/test/loader/__fixtures__/custom/foo/baz.md @@ -0,0 +1,5 @@ +--- +title: Baz +date: 2018-05-20 +--- +Life is so good diff --git a/test/loader/__fixtures__/custom/hello.md b/test/loader/__fixtures__/custom/hello.md index b846caae80..6d86ef4978 100644 --- a/test/loader/__fixtures__/custom/hello.md +++ b/test/loader/__fixtures__/custom/hello.md @@ -1,5 +1,6 @@ --- title: Hello, World ! +date: 2018-07-28 --- Hello World diff --git a/test/loader/__fixtures__/simple/hello.md b/test/loader/__fixtures__/simple/hello.md index b846caae80..6d86ef4978 100644 --- a/test/loader/__fixtures__/simple/hello.md +++ b/test/loader/__fixtures__/simple/hello.md @@ -1,5 +1,6 @@ --- title: Hello, World ! +date: 2018-07-28 --- Hello World diff --git a/test/loader/__snapshots__/blog.test.js.snap b/test/loader/__snapshots__/blog.test.js.snap new file mode 100644 index 0000000000..04dd3fe1ad --- /dev/null +++ b/test/loader/__snapshots__/blog.test.js.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadBlog custom 1`] = ` +Array [ + Object { + "content": " + +Hello World +", + "date": 2018-07-28T00:00:00.000Z, + "path": "/hello.html", + "title": "Hello, World !", + }, + Object { + "content": " + +Lorem ipsum +", + "date": 2018-06-20T00:00:00.000Z, + "path": "/foo/bar.html", + "title": "Lorem ipsum", + }, + Object { + "content": " +Life is so good +", + "date": 2018-05-20T00:00:00.000Z, + "path": "/foo/baz.html", + "title": "Baz", + }, +] +`; + +exports[`loadBlog simple 1`] = ` +Array [ + Object { + "content": " + +Hello World +", + "date": 2018-07-28T00:00:00.000Z, + "path": "/hello.html", + "title": "Hello, World !", + }, +] +`; diff --git a/test/loader/__snapshots__/config.test.js.snap b/test/loader/__snapshots__/config.test.js.snap new file mode 100644 index 0000000000..21049a5948 --- /dev/null +++ b/test/loader/__snapshots__/config.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadConfig custom 1`] = ` +Object { + "base": "blogi", + "description": "Hello World", + "dest": "blogi", + "title": "Hello World", +} +`; + +exports[`loadConfig simple 1`] = ` +Object { + "description": "Hello World", + "title": "Hello World", +} +`; diff --git a/test/loader/blog.test.js b/test/loader/blog.test.js new file mode 100644 index 0000000000..df36780dbc --- /dev/null +++ b/test/loader/blog.test.js @@ -0,0 +1,18 @@ +const path = require('path'); +const fs = require('fs'); +const loadBlog = require('../../lib/loader/blog'); + +describe('loadBlog', () => { + const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); + const customDir = path.join(__dirname, '__fixtures__', 'custom'); + + test('simple', async () => { + const blogDatas = await loadBlog(simpleDir); + expect(blogDatas).toMatchSnapshot(); + }); + + test('custom', async () => { + const blogDatas = await loadBlog(customDir); + expect(blogDatas).toMatchSnapshot(); + }); +}); diff --git a/test/loader/config.test.js b/test/loader/config.test.js index c4aab7892b..6965ac2dd6 100644 --- a/test/loader/config.test.js +++ b/test/loader/config.test.js @@ -7,22 +7,10 @@ describe('loadConfig', () => { const customDir = path.join(__dirname, '__fixtures__', 'custom'); test('simple', () => { - expect(loadConfig(simpleDir)).toMatchInlineSnapshot(` -Object { - "description": "Hello World", - "title": "Hello World", -} -`); + expect(loadConfig(simpleDir)).toMatchSnapshot(); }); test('custom', () => { - expect(loadConfig(customDir)).toMatchInlineSnapshot(` -Object { - "base": "blogi", - "description": "Hello World", - "dest": "blogi", - "title": "Hello World", -} -`); + expect(loadConfig(customDir)).toMatchSnapshot(); }); }); diff --git a/yarn.lock b/yarn.lock index 24dff61014..f48ee10b84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,6 +16,17 @@ esutils "^2.0.2" js-tokens "^3.0.0" +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.0.1": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a" + "@shellscape/koa-send@^4.1.0": version "4.1.3" resolved "https://registry.yarnpkg.com/@shellscape/koa-send/-/koa-send-4.1.3.tgz#1a7c8df21f63487e060b7bfd8ed82e1d3c4ae0b0" @@ -545,6 +556,100 @@ babel-generator@^6.18.0, babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" @@ -565,6 +670,12 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + babel-plugin-istanbul@^4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" @@ -578,10 +689,254 @@ babel-plugin-jest-hoist@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + babel-plugin-syntax-object-rest-spread@^6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + babel-preset-jest@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" @@ -601,7 +956,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -618,7 +973,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -632,7 +987,7 @@ babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.26.0: +babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -796,6 +1151,13 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -865,6 +1227,10 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -899,6 +1265,10 @@ camelize@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" +caniuse-lite@^1.0.30000844: + version "1.0.30000865" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" + capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" @@ -1445,6 +1815,13 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-glob@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -1497,6 +1874,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +electron-to-chromium@^1.3.47: + version "1.3.52" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" + elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -1920,6 +2301,17 @@ fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" +fast-glob@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf" + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.0.1" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.1" + micromatch "^3.1.10" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -2057,6 +2449,12 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +front-matter@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.3.0.tgz#7203af896ce357ee04e2aa45169ea91ed7f67504" + dependencies: + js-yaml "^3.10.0" + fs-extra@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" @@ -2158,6 +2556,10 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -2194,6 +2596,18 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +globby@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50" + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + fast-glob "^2.0.2" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -2385,7 +2799,7 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3: +ignore@^3.3.3, ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" @@ -3105,7 +3519,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1: +js-yaml@^3.10.0, js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: @@ -3151,6 +3565,10 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -3565,6 +3983,10 @@ merge-stream@^1.0.1: dependencies: readable-stream "^2.0.1" +merge2@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34" + merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -3587,7 +4009,7 @@ micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.1.4, micromatch@^3.1.8: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" dependencies: @@ -4300,7 +4722,7 @@ pretty-format@^23.2.0: ansi-regex "^3.0.0" ansi-styles "^3.2.0" -private@^0.1.8: +private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -4512,10 +4934,22 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -4533,6 +4967,14 @@ regexpp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -4546,6 +4988,16 @@ registry-url@^3.0.3: dependencies: rc "^1.0.1" +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + remove-array-items@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/remove-array-items/-/remove-array-items-1.0.0.tgz#07bf42cb332f4cf6e85ead83b5e4e896d2326b21" From 7116374adf85f0bb5c761e1cbbfb7e8111766e62 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 28 Jul 2018 18:48:37 +0800 Subject: [PATCH 005/135] chore(loader): prettier & eslint --- lib/loader/blog.js | 99 ++++++++++++++++++-------------------- lib/loader/config.js | 28 +++++------ lib/loader/index.js | 33 ++++++------- test/loader/blog.test.js | 35 +++++++------- test/loader/config.test.js | 31 ++++++------ 5 files changed, 108 insertions(+), 118 deletions(-) diff --git a/lib/loader/blog.js b/lib/loader/blog.js index c654e67096..6bb413ef7a 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -1,52 +1,47 @@ -const fs = require('fs-extra'); -const path = require('path'); -const fm = require('front-matter'); -const globby = require('globby'); -const indexRE = /(^|.*\/)index\.md$/i; -const extRE = /\.md$/; - -function fileToPath(file) { - if (indexRE.test(file)) { - // index.md -> / - // foo/index.md -> /foo/ - return file.replace(indexRE, '/$1'); - } else { - // foo.md -> /foo.html - // foo/bar.md -> /foo/bar.html - return `/${file.replace(extRE, '').replace(/\\/g, '/')}.html`; - } -} - -function parse(fileString) { - if (!fm.test(fileString)) { - return {metadata: null, content: fileString}; - } - const {attributes: metadata, body: content} = fm(fileString); - - return {metadata, content}; -} - -async function loadBlog(sourceDir) { - const blogFiles = await globby(['**/*.md', '!.blogi', '!node_modules'], { - cwd: sourceDir - }); - - const blogDatas = await Promise.all( - blogFiles.map(async file => { - const filepath = path.resolve(sourceDir, file); - const fileString = await fs.readFile(filepath, 'utf-8'); - const {metadata, content} = parse(fileString); - - return { - path: fileToPath(file), - content: content, - title: metadata.title, - date: metadata.date - }; - }) - ); - blogDatas.sort((a, b) => b.date - a.date); - return blogDatas; -} - -module.exports = loadBlog; +const fs = require('fs-extra'); +const path = require('path'); +const fm = require('front-matter'); +const globby = require('globby'); +const indexRE = /(^|.*\/)index\.md$/i; +const mdRE = /\.md$/; + +function fileToPath(file) { + if (indexRE.test(file)) { + return file.replace(indexRE, '/$1'); + } + return `/${file.replace(mdRE, '').replace(/\\/g, '/')}.html`; +} + +function parse(fileString) { + if (!fm.test(fileString)) { + return {metadata: null, content: fileString}; + } + const {attributes: metadata, body: content} = fm(fileString); + + return {metadata, content}; +} + +async function loadBlog(sourceDir) { + const blogFiles = await globby(['**/*.md', '!.blogi', '!node_modules'], { + cwd: sourceDir + }); + + const blogDatas = await Promise.all( + blogFiles.map(async file => { + const filepath = path.resolve(sourceDir, file); + const fileString = await fs.readFile(filepath, 'utf-8'); + const {metadata, content} = parse(fileString); + + return { + path: fileToPath(file), + content, + title: metadata.title, + date: metadata.date + }; + }) + ); + blogDatas.sort((a, b) => b.date - a.date); + return blogDatas; +} + +module.exports = loadBlog; diff --git a/lib/loader/config.js b/lib/loader/config.js index 78ce9260d3..38fd0201f9 100644 --- a/lib/loader/config.js +++ b/lib/loader/config.js @@ -1,14 +1,14 @@ -const fs = require('fs-extra'); -const path = require('path'); - -module.exports = function loadConfig(sourceDir, deleteCache = true) { - const configPath = path.resolve(sourceDir, '.blogi', 'config.js'); - if (deleteCache) { - delete require.cache[configPath]; - } - let config = {}; - if (fs.existsSync(configPath)) { - config = require(configPath); - } - return config; -}; +const fs = require('fs-extra'); +const path = require('path'); + +module.exports = function loadConfig(sourceDir, deleteCache = true) { + const configPath = path.resolve(sourceDir, '.blogi', 'config.js'); + if (deleteCache) { + delete require.cache[configPath]; + } + let config = {}; + if (fs.existsSync(configPath)) { + config = require(configPath); // eslint-disable-line + } + return config; +}; diff --git a/lib/loader/index.js b/lib/loader/index.js index d983770936..3953b03a45 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -1,18 +1,15 @@ -const path = require('path'); -const loadConfig = require('./config'); -const loadBlog = require('./blog'); - -module.exports = async function load(sourceDir) { - // 1. load siteConfig - const siteConfig = loadConfig(sourceDir); - - // 2. extract data from all blog files - const blogDatas = await loadBlog(sourceDir); - - // 3. TODO - - return { - siteConfig, - blogDatas - }; -}; +const loadConfig = require('./config'); +const loadBlog = require('./blog'); + +module.exports = async function load(sourceDir) { + // 1. load siteConfig + const siteConfig = loadConfig(sourceDir); + + // 2. extract data from all blog files + const blogDatas = await loadBlog(sourceDir); + + return { + siteConfig, + blogDatas + }; +}; diff --git a/test/loader/blog.test.js b/test/loader/blog.test.js index df36780dbc..28f61e0b90 100644 --- a/test/loader/blog.test.js +++ b/test/loader/blog.test.js @@ -1,18 +1,17 @@ -const path = require('path'); -const fs = require('fs'); -const loadBlog = require('../../lib/loader/blog'); - -describe('loadBlog', () => { - const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); - const customDir = path.join(__dirname, '__fixtures__', 'custom'); - - test('simple', async () => { - const blogDatas = await loadBlog(simpleDir); - expect(blogDatas).toMatchSnapshot(); - }); - - test('custom', async () => { - const blogDatas = await loadBlog(customDir); - expect(blogDatas).toMatchSnapshot(); - }); -}); +const path = require('path'); +const loadBlog = require('../../lib/loader/blog'); + +describe('loadBlog', () => { + const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); + const customDir = path.join(__dirname, '__fixtures__', 'custom'); + + test('simple', async () => { + const blogDatas = await loadBlog(simpleDir); + expect(blogDatas).toMatchSnapshot(); + }); + + test('custom', async () => { + const blogDatas = await loadBlog(customDir); + expect(blogDatas).toMatchSnapshot(); + }); +}); diff --git a/test/loader/config.test.js b/test/loader/config.test.js index 6965ac2dd6..f1b137dbdf 100644 --- a/test/loader/config.test.js +++ b/test/loader/config.test.js @@ -1,16 +1,15 @@ -const path = require('path'); -const fs = require('fs'); -const loadConfig = require('../../lib/loader/config'); - -describe('loadConfig', () => { - const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); - const customDir = path.join(__dirname, '__fixtures__', 'custom'); - - test('simple', () => { - expect(loadConfig(simpleDir)).toMatchSnapshot(); - }); - - test('custom', () => { - expect(loadConfig(customDir)).toMatchSnapshot(); - }); -}); +const path = require('path'); +const loadConfig = require('../../lib/loader/config'); + +describe('loadConfig', () => { + const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); + const customDir = path.join(__dirname, '__fixtures__', 'custom'); + + test('simple', () => { + expect(loadConfig(simpleDir)).toMatchSnapshot(); + }); + + test('custom', () => { + expect(loadConfig(customDir)).toMatchSnapshot(); + }); +}); From 2ab412e563e4aa7ac87d05edaa05ebbfb4c7d8d1 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 28 Jul 2018 20:24:09 +0800 Subject: [PATCH 006/135] feat: add simple webpack config --- lib/webpack/base.js | 55 +++++++++++++++++++++++++++++++++++++++++++++ lib/webpack/dev.js | 10 +++++++++ 2 files changed, 65 insertions(+) create mode 100644 lib/webpack/base.js create mode 100644 lib/webpack/dev.js diff --git a/lib/webpack/base.js b/lib/webpack/base.js new file mode 100644 index 0000000000..c7970dfcfd --- /dev/null +++ b/lib/webpack/base.js @@ -0,0 +1,55 @@ +const Config = require('webpack-chain'); +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = function createBaseConfig(props) { + const {outDir, themePath, sourceDir} = props; + + const config = new Config(); + const isProd = process.env.NODE_ENV === 'production'; + + config + .mode(isProd ? 'production' : 'development') + .output.path(outDir) + .filename(isProd ? '[name].[chunkhash].js' : '[name].js') + .publicPath(isProd ? publicPath : '/'); + + config.resolve + .set('symlinks', true) + .alias.set('@theme', themePath) + .set('@source', sourceDir) + .set('@core', path.resolve(__dirname, '../core')) + .end(); + + const libDir = path.join(__dirname, '..'); + config.module + .rule('js') + .test(/\.js$/) + .exclude.add(filepath => { + // Always transpile lib directory + if (filepath.startsWith(libDir)) { + return false; + } + // Don't transpile node_modules + return /node_modules/.test(filepath); + }) + .end() + .use('babel') + .loader('babel-loader') + .options({ + // do not pick local project babel config + babelrc: false, + presets: ['env', 'react'] + }); + + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + inject: false, + hash: true, + template: path.resolve(__dirname, '../core/index.html'), + filename: 'index.html' + } + ]); + + return config; +}; diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js new file mode 100644 index 0000000000..6b420c559c --- /dev/null +++ b/lib/webpack/dev.js @@ -0,0 +1,10 @@ +const path = require('path'); +const createBaseConfig = require('./base'); + +module.exports = function createDevConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/index.js')); + + return config; +}; From 333574efe61b460aade07299bfbf5e9f652b7e1e Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 28 Jul 2018 20:25:38 +0800 Subject: [PATCH 007/135] feat: prototype dev server --- .babelrc | 11 +- .eslintrc.js | 3 +- .prettierrc | 14 +- lib/core/index.html | 12 ++ lib/core/index.js | 10 ++ lib/dev.js | 95 ++++++++++- lib/loader/blog.js | 1 + lib/loader/index.js | 26 ++- lib/theme/index.js | 3 + package.json | 8 +- yarn.lock | 379 ++++++++++++++++++++++++++++++++++++++++++-- 11 files changed, 524 insertions(+), 38 deletions(-) create mode 100644 lib/core/index.html create mode 100644 lib/core/index.js create mode 100644 lib/theme/index.js diff --git a/.babelrc b/.babelrc index 3fea2ed8ac..e7f5d14542 100644 --- a/.babelrc +++ b/.babelrc @@ -1,10 +1,3 @@ { - "env": { - "test": { - "presets": [ - ["env", { "targets": { "node": 8 }}] - ] - } - } - } - \ No newline at end of file + "presets": ["env", "react"] +} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 25293f3037..da650e9416 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -13,6 +13,7 @@ module.exports = { rules: { 'no-console': OFF, 'func-names': OFF, - 'react/jsx-filename-extension': OFF, // Enable in future when migrating. + 'react/jsx-filename-extension': OFF, + 'react/jsx-one-expression-per-line': OFF, }, }; \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 61480c22e5..35d2a42845 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,8 @@ { - "bracketSpacing": false, - "jsxBracketSameLine": true, - "parser": "flow", - "printWidth": 80, - "proseWrap": "never", - "singleQuote": true - } \ No newline at end of file + "bracketSpacing": false, + "jsxBracketSameLine": true, + "parser": "flow", + "printWidth": 80, + "proseWrap": "never", + "singleQuote": true +} \ No newline at end of file diff --git a/lib/core/index.html b/lib/core/index.html new file mode 100644 index 0000000000..57c2334380 --- /dev/null +++ b/lib/core/index.html @@ -0,0 +1,12 @@ + + + + + + + + +
+ + + \ No newline at end of file diff --git a/lib/core/index.js b/lib/core/index.js new file mode 100644 index 0000000000..f6c2cf147b --- /dev/null +++ b/lib/core/index.js @@ -0,0 +1,10 @@ +import React from 'react'; +import {render} from 'react-dom'; +import theme from '@theme'; + +class App extends React.Component { + render() { + return
Hello world! {theme()}
; + } +} +render(, document.getElementById('app')); diff --git a/lib/dev.js b/lib/dev.js index 393be03951..3ec45e4e62 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -1,3 +1,92 @@ -module.exports = async function dev(sourceDir, cliOptions = {}) { - console.log('Development'); -}; +const ora = require('ora'); +const path = require('path'); +const chalk = require('chalk'); +const webpack = require('webpack'); +const fs = require('fs-extra'); +const chokidar = require('chokidar'); +const serve = require('webpack-serve'); +const convert = require('koa-connect'); +const mount = require('koa-mount'); +const range = require('koa-range'); +const serveStatic = require('koa-static'); +const history = require('connect-history-api-fallback'); +const load = require('./loader'); +const createDevConfig = require('./webpack/dev'); + +module.exports = async function dev(sourceDir, cliOptions = {}) { + const logger = ora(chalk.blue('Start development server')).start(); + + // load site props from preprocessed files in source directory + const props = await load(sourceDir); + + // Reload for any add/remove of file + const reload = () => { + const reloadLogger = ora({ + color: 'green', + text: chalk.green('Reloading files') + }).start(); + load(sourceDir) + .then(() => { + setTimeout(() => { + reloadLogger.stop(); + }, 1000); + }) + .catch(err => { + console.error(chalk.red(err.stack)); + }); + }; + const fsWatcher = chokidar.watch(['**/*.md'], { + cwd: sourceDir, + ignoreInitial: true + }); + fsWatcher.on('add', reload); + fsWatcher.on('change', reload); + fsWatcher.on('unlink', reload); + fsWatcher.on('addDir', reload); + fsWatcher.on('unlinkDir', reload); + + // resolve webpack config + let config = createDevConfig(props); + + // create compiler from generated webpack config + config = config.toConfig(); + const compiler = webpack(config); + logger.succeed(); + + // webpack-serve + const serveContentDir = path.resolve(__dirname, 'serveContent'); + const port = cliOptions.port || 8080; + await serve( + {}, + { + content: [serveContentDir], + compiler, + devWare: {logLevel: 'warn'}, + hotClient: { + port: port + 1, + logLevel: 'error' + }, + logLevel: 'error', + port, + add: app => { + const userPublic = path.resolve(sourceDir, '.blogi/public'); + + // enable range request + app.use(range); + + // respect base when serving static files... + if (fs.existsSync(userPublic)) { + app.use(mount(props.publicPath, serveStatic(userPublic))); + } + + app.use( + convert( + history({ + rewrites: [{from: /\.html$/, to: '/'}] + }) + ) + ); + } + } + ); +}; diff --git a/lib/loader/blog.js b/lib/loader/blog.js index 6bb413ef7a..58f8a0d992 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -2,6 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const fm = require('front-matter'); const globby = require('globby'); + const indexRE = /(^|.*\/)index\.md$/i; const mdRE = /\.md$/; diff --git a/lib/loader/index.js b/lib/loader/index.js index 3953b03a45..a808bf23dc 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -1,15 +1,35 @@ +const fs = require('fs-extra'); +const path = require('path'); const loadConfig = require('./config'); const loadBlog = require('./blog'); module.exports = async function load(sourceDir) { - // 1. load siteConfig + // load siteConfig const siteConfig = loadConfig(sourceDir); - // 2. extract data from all blog files + // extract data from all blog files const blogDatas = await loadBlog(sourceDir); + // resolve outDir + const outDir = siteConfig.dest + ? path.resolve(siteConfig.dest) + : path.resolve(sourceDir, '.blogi/dist'); + + // resolve the path of our app theme/ layout + const themePath = + !siteConfig.themePath || + !fs.existsSync(path.resolve(sourceDir, siteConfig.themePath)) + ? path.resolve(__dirname, '../theme') + : siteConfig.themePath; + + const publicPath = siteConfig.base || '/'; + return { siteConfig, - blogDatas + blogDatas, + sourceDir, + outDir, + themePath, + publicPath }; }; diff --git a/lib/theme/index.js b/lib/theme/index.js new file mode 100644 index 0000000000..5da5e8bf31 --- /dev/null +++ b/lib/theme/index.js @@ -0,0 +1,3 @@ +module.exports = function theme() { + return 'theme'; +}; diff --git a/package.json b/package.json index 95e52a68b4..33a4644c9f 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ }, "homepage": "https://github.com/endiliey/blogi#readme", "devDependencies": { - "babel-preset-env": "^1.7.0", "eslint": "^4.19.1", "eslint-config-airbnb": "17.0.0", "eslint-config-prettier": "^2.9.0", @@ -40,6 +39,10 @@ "prettier": "^1.13.7" }, "dependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.5", + "babel-preset-env": "^1.7.0", + "babel-preset-react": "^6.24.1", "chalk": "^2.4.1", "chokidar": "^2.0.4", "commander": "^2.16.0", @@ -47,12 +50,15 @@ "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", + "html-webpack-plugin": "^3.2.0", "koa-connect": "^2.0.1", "koa-convert": "^1.2.0", "koa-mount": "^3.0.0", "koa-range": "^0.3.0", "koa-static": "^5.0.0", "ora": "^3.0.0", + "react": "^16.4.1", + "react-dom": "^16.4.1", "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", diff --git a/yarn.lock b/yarn.lock index f48ee10b84..284587c26f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -437,6 +437,10 @@ arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -519,7 +523,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.0.0, babel-core@^6.26.0: +babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.26.3: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: @@ -564,6 +568,14 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" @@ -664,6 +676,14 @@ babel-jest@^23.4.2: babel-plugin-istanbul "^4.1.6" babel-preset-jest "^23.2.0" +babel-loader@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68" + dependencies: + find-cache-dir "^1.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" @@ -697,6 +717,14 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + babel-plugin-syntax-object-rest-spread@^6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -889,6 +917,41 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-flow-strip-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-display-name@^6.23.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" @@ -937,6 +1000,12 @@ babel-preset-env@^1.7.0: invariant "^2.2.2" semver "^5.3.0" +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + babel-preset-jest@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" @@ -944,6 +1013,17 @@ babel-preset-jest@^23.2.0: babel-plugin-jest-hoist "^23.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" + dependencies: + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -1042,6 +1122,10 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -1245,6 +1329,13 @@ callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + camelcase-keys@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" @@ -1365,6 +1456,12 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-css@4.1.x: + version "4.1.11" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.11.tgz#2ecdf145aba38f54740f26cefd0ff3e03e125d6a" + dependencies: + source-map "0.5.x" + cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" @@ -1441,7 +1538,7 @@ combined-stream@1.0.6, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@^2.11.0, commander@^2.16.0: +commander@2.16.x, commander@^2.11.0, commander@^2.16.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" @@ -1541,6 +1638,10 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -1619,6 +1720,19 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" @@ -1835,16 +1949,56 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" dependencies: webidl-conversions "^4.0.2" +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -1898,6 +2052,12 @@ emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -1912,6 +2072,10 @@ enhanced-resolve@^4.1.0: memory-fs "^0.4.0" tapable "^1.0.0" +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -2326,6 +2490,18 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fbjs@^0.8.16: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2722,6 +2898,10 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +he@1.1.x: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2747,6 +2927,39 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" +html-minifier@^3.2.3: + version "3.5.19" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.19.tgz#ed53c4b7326fe507bc3a1adbcc3bbb56660a2ebd" + dependencies: + camel-case "3.0.x" + clean-css "4.1.x" + commander "2.16.x" + he "1.1.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.4.x" + +html-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + http-assert@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" @@ -2779,7 +2992,7 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.17, iconv-lite@^0.4.4: +iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -3109,7 +3322,7 @@ is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3133,6 +3346,10 @@ is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -3151,6 +3368,13 @@ isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -3808,7 +4032,16 @@ loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" -loader-utils@^1.1.0: +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" dependencies: @@ -3831,7 +4064,7 @@ lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -3860,7 +4093,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: @@ -3873,6 +4106,10 @@ loud-rejection@^1.0.0, loud-rejection@^1.6.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -4221,6 +4458,19 @@ next-tick@1: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + dependencies: + lower-case "^1.1.1" + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4329,6 +4579,12 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -4545,6 +4801,12 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + parse-asn1@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" @@ -4715,6 +4977,13 @@ prettier@^1.13.7: version "1.13.7" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" +pretty-error@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" + dependencies: + renderkid "^2.0.1" + utila "~0.4" + pretty-format@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.2.0.tgz#3b0aaa63c018a53583373c1cb3a5d96cc5e83017" @@ -4742,6 +5011,12 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + prompts@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.13.tgz#7fad7ee1c6cafe49834ca0b2a6a471262de57620" @@ -4749,7 +5024,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.6.2: +prop-types@^15.6.0, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -4855,6 +5130,24 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^16.4.1: + version "16.4.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +react@^16.4.1: + version "16.4.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -4912,6 +5205,15 @@ read-pkg@^3.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -4998,6 +5300,10 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + remove-array-items@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/remove-array-items/-/remove-array-items-1.0.0.tgz#07bf42cb332f4cf6e85ead83b5e4e896d2326b21" @@ -5006,6 +5312,16 @@ remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" +renderkid@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" @@ -5245,7 +5561,7 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -5350,16 +5666,16 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -5496,6 +5812,10 @@ string_decoder@^1.0.0, string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -5678,6 +5998,10 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toposort@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" + tough-cookie@>=2.3.3, tough-cookie@^2.3.4: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -5740,6 +6064,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +ua-parser-js@^0.7.18: + version "0.7.18" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" + uglify-es@^3.3.4: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -5747,6 +6075,13 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" +uglify-js@3.4.x: + version "3.4.6" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.6.tgz#bc546d53f3e02b05d97d0ca5a7abfe0fb0384ddb" + dependencies: + commander "~2.16.0" + source-map "~0.6.1" + uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -5834,6 +6169,10 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + uri-js@^4.2.1: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -5869,7 +6208,7 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util.promisify@^1.0.0: +util.promisify@1.0.0, util.promisify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" dependencies: @@ -5888,6 +6227,14 @@ util@^0.10.3: dependencies: inherits "2.0.3" +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + uuid@^3.1.0: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -6078,6 +6425,10 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.19" +whatwg-fetch@>=0.10.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" From 0bbe7fd9990980ad565368272f654758ae6ddb0f Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 01:06:25 +0800 Subject: [PATCH 008/135] chore: .gitignore & add config for demo --- .gitignore | 1 + blog/.blogi/config.js | 4 ++++ blog/hello-world.md | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 blog/.blogi/config.js diff --git a/.gitignore b/.gitignore index c47a0349c6..c9da630db9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules dist yarn-error.log +generated diff --git a/blog/.blogi/config.js b/blog/.blogi/config.js new file mode 100644 index 0000000000..14da102249 --- /dev/null +++ b/blog/.blogi/config.js @@ -0,0 +1,4 @@ +module.exports = { + title: 'Hello World', + description: 'Hello World' +}; diff --git a/blog/hello-world.md b/blog/hello-world.md index 13d9ddfec8..1dbbb2e3c2 100644 --- a/blog/hello-world.md +++ b/blog/hello-world.md @@ -1,12 +1,12 @@ ---- -title: Hello, World ! -author: Endilie Yacop Sucipto -authorURL: http://twitter.com/endiliey -authorFBID: 100000251103620 ---- - -Hi, Endilie here. - - - -Random thoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. +--- +title: Hello, World ! +author: Endilie Yacop Sucipto +authorURL: http://twitter.com/endiliey +authorFBID: 100000251103620 +--- + +Hi, Endilie here. + + + +Random thoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. From 56dfec19ea9bff0a1ac5dd867d9a97f3857be830 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 01:07:08 +0800 Subject: [PATCH 009/135] feat(webpack): add better log output --- lib/dev.js | 38 ++++++++++++++++++++------------------ lib/webpack/plugin/log.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 lib/webpack/plugin/log.js diff --git a/lib/dev.js b/lib/dev.js index 3ec45e4e62..0187c07279 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -12,6 +12,7 @@ const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); +const logPlugin = require('./webpack/plugin/log') module.exports = async function dev(sourceDir, cliOptions = {}) { const logger = ora(chalk.blue('Start development server')).start(); @@ -19,21 +20,11 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // load site props from preprocessed files in source directory const props = await load(sourceDir); - // Reload for any add/remove of file + // Reload for any add/change/remove of file const reload = () => { - const reloadLogger = ora({ - color: 'green', - text: chalk.green('Reloading files') - }).start(); - load(sourceDir) - .then(() => { - setTimeout(() => { - reloadLogger.stop(); - }, 1000); - }) - .catch(err => { - console.error(chalk.red(err.stack)); - }); + load(sourceDir).catch(err => { + console.error(chalk.red(err.stack)); + }); }; const fsWatcher = chokidar.watch(['**/*.md'], { cwd: sourceDir, @@ -48,20 +39,31 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // resolve webpack config let config = createDevConfig(props); + const port = cliOptions.port || 8080; + + config + .plugin('blogi-log') + .use(logPlugin, [{ + port, + publicPath: props.publicPath + }]); + // create compiler from generated webpack config config = config.toConfig(); const compiler = webpack(config); logger.succeed(); // webpack-serve - const serveContentDir = path.resolve(__dirname, 'serveContent'); - const port = cliOptions.port || 8080; await serve( {}, { - content: [serveContentDir], + content: [path.resolve(__dirname, 'serveContent')], compiler, - devWare: {logLevel: 'warn'}, + open: true, + devMiddleware: { + logLevel: 'warn', + publicPath: props.publicPath + }, hotClient: { port: port + 1, logLevel: 'error' diff --git a/lib/webpack/plugin/log.js b/lib/webpack/plugin/log.js new file mode 100644 index 0000000000..60420ea7f8 --- /dev/null +++ b/lib/webpack/plugin/log.js @@ -0,0 +1,29 @@ +const chalk = require('chalk'); +const ora = require('ora'); +module.exports = class LogPlugin { + constructor (options) { + this.options = options + } + + apply (compiler) { + const logger = ora(); + let isFirst = true + compiler.hooks.done.tap('blogi-log', stats => { + clearScreen() + + const { port, publicPath } = this.options + const time = new Date().toTimeString().match(/^[\d:]+/)[0] + + logger.succeed(`${chalk.gray(`[${time}]`)} Build ${chalk.yellow(stats.hash.slice(0, 6))} finished in ${chalk.green(stats.endTime - stats.startTime)} ms!`) + if (isFirst) { + isFirst = false + console.log(`\n${chalk.gray('>')} Blogi dev server listening at ${chalk.cyan(`http://localhost:${port}${publicPath}`)}`) + } + }) + compiler.hooks.invalid.tap('blogi-log', clearScreen) + } +} + +function clearScreen () { + process.stdout.write('\x1Bc') +} \ No newline at end of file From e8e1d5e097c4999bddd5b524c26fdbbf7b974b16 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 01:14:32 +0800 Subject: [PATCH 010/135] chore: prettier & eslint --- .eslintrc.js | 2 ++ lib/build.js | 9 +++++---- lib/dev.js | 17 +++++++++-------- lib/theme/index.js | 6 +++--- lib/webpack/base.js | 3 ++- lib/webpack/log.js | 34 ++++++++++++++++++++++++++++++++++ lib/webpack/plugin/log.js | 29 ----------------------------- 7 files changed, 55 insertions(+), 45 deletions(-) create mode 100644 lib/webpack/log.js delete mode 100644 lib/webpack/plugin/log.js diff --git a/.eslintrc.js b/.eslintrc.js index da650e9416..6f297e956d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,5 +15,7 @@ module.exports = { 'func-names': OFF, 'react/jsx-filename-extension': OFF, 'react/jsx-one-expression-per-line': OFF, + 'import/no-unresolved': WARNING, // because it couldn't resolve webpack alias + 'react/prefer-stateless-function': WARNING, }, }; \ No newline at end of file diff --git a/lib/build.js b/lib/build.js index 5b1054a533..34dd734731 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,4 +1,5 @@ -module.exports = async function build(sourceDir, cliOptions = {}) { - process.env.NODE_ENV = 'production'; - console.log('Build'); -}; +module.exports = async function build(sourceDir, cliOptions = {}) { + process.env.NODE_ENV = 'production'; + console.log(cliOptions); + console.log('Build'); +}; diff --git a/lib/dev.js b/lib/dev.js index 0187c07279..8b2985053c 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -12,7 +12,7 @@ const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); -const logPlugin = require('./webpack/plugin/log') +const logPlugin = require('./webpack/log'); module.exports = async function dev(sourceDir, cliOptions = {}) { const logger = ora(chalk.blue('Start development server')).start(); @@ -40,13 +40,14 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { let config = createDevConfig(props); const port = cliOptions.port || 8080; + const {publicPath} = props; - config - .plugin('blogi-log') - .use(logPlugin, [{ - port, - publicPath: props.publicPath - }]); + config.plugin('blogi-log').use(logPlugin, [ + { + port, + publicPath + } + ]); // create compiler from generated webpack config config = config.toConfig(); @@ -62,7 +63,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { open: true, devMiddleware: { logLevel: 'warn', - publicPath: props.publicPath + publicPath }, hotClient: { port: port + 1, diff --git a/lib/theme/index.js b/lib/theme/index.js index 5da5e8bf31..cae5be8cc5 100644 --- a/lib/theme/index.js +++ b/lib/theme/index.js @@ -1,3 +1,3 @@ -module.exports = function theme() { - return 'theme'; -}; +module.exports = function theme() { + return 'themes'; +}; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index c7970dfcfd..995f7f22de 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -3,7 +3,7 @@ const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = function createBaseConfig(props) { - const {outDir, themePath, sourceDir} = props; + const {outDir, themePath, sourceDir, publicPath} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -18,6 +18,7 @@ module.exports = function createBaseConfig(props) { .set('symlinks', true) .alias.set('@theme', themePath) .set('@source', sourceDir) + .set('@generated', path.resolve(__dirname, '../generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); diff --git a/lib/webpack/log.js b/lib/webpack/log.js new file mode 100644 index 0000000000..6ca1677e71 --- /dev/null +++ b/lib/webpack/log.js @@ -0,0 +1,34 @@ +const chalk = require('chalk'); +const ora = require('ora'); + +function clearScreen() { + process.stdout.write('\x1Bc'); +} + +module.exports = class LogPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + const logger = ora(); + compiler.hooks.done.tap('blogi-log', stats => { + clearScreen(); + + const {port, publicPath} = this.options; + const time = new Date().toTimeString().match(/^[\d:]+/)[0]; + + logger.succeed( + `${chalk.gray(`[${time}]`)} Build ${chalk.green( + stats.hash.slice(0, 8) + )} finished in ${chalk.green(stats.endTime - stats.startTime)} ms!` + ); + console.log( + `\n${chalk.blue('Development server available at ')}${chalk.cyan( + `http://localhost:${port}${publicPath}` + )}` + ); + }); + compiler.hooks.invalid.tap('blogi-log', clearScreen); + } +}; diff --git a/lib/webpack/plugin/log.js b/lib/webpack/plugin/log.js deleted file mode 100644 index 60420ea7f8..0000000000 --- a/lib/webpack/plugin/log.js +++ /dev/null @@ -1,29 +0,0 @@ -const chalk = require('chalk'); -const ora = require('ora'); -module.exports = class LogPlugin { - constructor (options) { - this.options = options - } - - apply (compiler) { - const logger = ora(); - let isFirst = true - compiler.hooks.done.tap('blogi-log', stats => { - clearScreen() - - const { port, publicPath } = this.options - const time = new Date().toTimeString().match(/^[\d:]+/)[0] - - logger.succeed(`${chalk.gray(`[${time}]`)} Build ${chalk.yellow(stats.hash.slice(0, 6))} finished in ${chalk.green(stats.endTime - stats.startTime)} ms!`) - if (isFirst) { - isFirst = false - console.log(`\n${chalk.gray('>')} Blogi dev server listening at ${chalk.cyan(`http://localhost:${port}${publicPath}`)}`) - } - }) - compiler.hooks.invalid.tap('blogi-log', clearScreen) - } -} - -function clearScreen () { - process.stdout.write('\x1Bc') -} \ No newline at end of file From b1e785b6c3aae21e5b4a4e455d5c9900aa501370 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 02:04:42 +0800 Subject: [PATCH 011/135] feat: prototype building dynamic react route --- lib/core/index.js | 28 ++++++++++++++++-- lib/theme/hello.js | 5 ++++ lib/theme/index.js | 3 -- lib/theme/layout.js | 5 ++++ package.json | 1 + yarn.lock | 69 +++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 lib/theme/hello.js delete mode 100644 lib/theme/index.js create mode 100644 lib/theme/layout.js diff --git a/lib/core/index.js b/lib/core/index.js index f6c2cf147b..e3df9e0240 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -1,10 +1,34 @@ import React from 'react'; import {render} from 'react-dom'; -import theme from '@theme'; +import {BrowserRouter, Route, Switch} from 'react-router-dom'; +import Hello from '@theme/hello'; +import Layout from '@theme/layout'; class App extends React.Component { render() { - return
Hello world! {theme()}
; + // https://reacttraining.com/react-router/web/example/route-config + const routes = [ + { + path: '/', + component: Hello + }, + { + path: '/layout', + component: Layout + } + ]; + + return ( + +
+ + {routes.map(({path, component}) => ( + + ))} + +
+
+ ); } } render(, document.getElementById('app')); diff --git a/lib/theme/hello.js b/lib/theme/hello.js new file mode 100644 index 0000000000..1b334b8962 --- /dev/null +++ b/lib/theme/hello.js @@ -0,0 +1,5 @@ +const React = require('react'); + +const Hello = props => 'Hello'; + +module.exports = Hello; diff --git a/lib/theme/index.js b/lib/theme/index.js deleted file mode 100644 index cae5be8cc5..0000000000 --- a/lib/theme/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = function theme() { - return 'themes'; -}; diff --git a/lib/theme/layout.js b/lib/theme/layout.js new file mode 100644 index 0000000000..580297b680 --- /dev/null +++ b/lib/theme/layout.js @@ -0,0 +1,5 @@ +const React = require('react'); + +const Layout = props => 'Layout'; + +module.exports = Layout; diff --git a/package.json b/package.json index 33a4644c9f..f822724a91 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "ora": "^3.0.0", "react": "^16.4.1", "react-dom": "^16.4.1", + "react-router-dom": "^4.3.1", "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", diff --git a/yarn.lock b/yarn.lock index 284587c26f..7bff2ddd39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2902,6 +2902,16 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +history@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" + dependencies: + invariant "^2.2.1" + loose-envify "^1.2.0" + resolve-pathname "^2.2.0" + value-equal "^0.4.0" + warning "^3.0.0" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2910,6 +2920,10 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^2.5.0: + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3077,7 +3091,7 @@ inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" -invariant@^2.2.2: +invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: @@ -4093,7 +4107,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: @@ -4885,6 +4899,12 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -5024,7 +5044,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.6.0, prop-types@^15.6.2: +prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -5139,6 +5159,29 @@ react-dom@^16.4.1: object-assign "^4.1.1" prop-types "^15.6.0" +react-router-dom@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" + dependencies: + history "^4.7.2" + invariant "^2.2.4" + loose-envify "^1.3.1" + prop-types "^15.6.1" + react-router "^4.3.1" + warning "^4.0.1" + +react-router@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e" + dependencies: + history "^4.7.2" + hoist-non-react-statics "^2.5.0" + invariant "^2.2.4" + loose-envify "^1.3.1" + path-to-regexp "^1.7.0" + prop-types "^15.6.1" + warning "^4.0.1" + react@^16.4.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32" @@ -5411,6 +5454,10 @@ resolve-path@^1.3.3, resolve-path@^1.4.0: http-errors "~1.6.2" path-is-absolute "1.0.1" +resolve-pathname@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -6250,6 +6297,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-equal@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" + vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -6280,6 +6331,18 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + +warning@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745" + dependencies: + loose-envify "^1.0.0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" From 8b381777bcd409172a50ef008c3cac0521b00572 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 14:54:34 +0800 Subject: [PATCH 012/135] chore: remove unused variables --- lib/core/index.js | 1 - lib/dev.js | 37 ++++++---------------------------- lib/webpack/log.js | 2 +- package.json | 5 ----- yarn.lock | 49 ++++------------------------------------------ 5 files changed, 11 insertions(+), 83 deletions(-) diff --git a/lib/core/index.js b/lib/core/index.js index e3df9e0240..dbe96b255c 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -6,7 +6,6 @@ import Layout from '@theme/layout'; class App extends React.Component { render() { - // https://reacttraining.com/react-router/web/example/route-config const routes = [ { path: '/', diff --git a/lib/dev.js b/lib/dev.js index 8b2985053c..340f86db23 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -1,21 +1,16 @@ const ora = require('ora'); const path = require('path'); +const fs = require('fs-extra'); const chalk = require('chalk'); const webpack = require('webpack'); -const fs = require('fs-extra'); const chokidar = require('chokidar'); const serve = require('webpack-serve'); -const convert = require('koa-connect'); -const mount = require('koa-mount'); -const range = require('koa-range'); -const serveStatic = require('koa-static'); -const history = require('connect-history-api-fallback'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); -const logPlugin = require('./webpack/log'); +const blogiLog = require('./webpack/log'); module.exports = async function dev(sourceDir, cliOptions = {}) { - const logger = ora(chalk.blue('Start development server')).start(); + const logger = ora(chalk.blue('Starting development server')).start(); // load site props from preprocessed files in source directory const props = await load(sourceDir); @@ -42,7 +37,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { const port = cliOptions.port || 8080; const {publicPath} = props; - config.plugin('blogi-log').use(logPlugin, [ + config.plugin('blogi-log').use(blogiLog, [ { port, publicPath @@ -58,9 +53,8 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { await serve( {}, { - content: [path.resolve(__dirname, 'serveContent')], compiler, - open: true, + open: false, // don't open browser automatically devMiddleware: { logLevel: 'warn', publicPath @@ -70,26 +64,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { logLevel: 'error' }, logLevel: 'error', - port, - add: app => { - const userPublic = path.resolve(sourceDir, '.blogi/public'); - - // enable range request - app.use(range); - - // respect base when serving static files... - if (fs.existsSync(userPublic)) { - app.use(mount(props.publicPath, serveStatic(userPublic))); - } - - app.use( - convert( - history({ - rewrites: [{from: /\.html$/, to: '/'}] - }) - ) - ); - } + port } ); }; diff --git a/lib/webpack/log.js b/lib/webpack/log.js index 6ca1677e71..1316d961b9 100644 --- a/lib/webpack/log.js +++ b/lib/webpack/log.js @@ -5,7 +5,7 @@ function clearScreen() { process.stdout.write('\x1Bc'); } -module.exports = class LogPlugin { +module.exports = class BlogiLog { constructor(options) { this.options = options; } diff --git a/package.json b/package.json index f822724a91..823e92910e 100644 --- a/package.json +++ b/package.json @@ -46,16 +46,11 @@ "chalk": "^2.4.1", "chokidar": "^2.0.4", "commander": "^2.16.0", - "connect-history-api-fallback": "^1.5.0", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", "html-webpack-plugin": "^3.2.0", - "koa-connect": "^2.0.1", "koa-convert": "^1.2.0", - "koa-mount": "^3.0.0", - "koa-range": "^0.3.0", - "koa-static": "^5.0.0", "ora": "^3.0.0", "react": "^16.4.1", "react-dom": "^16.4.1", diff --git a/yarn.lock b/yarn.lock index 7bff2ddd39..35de9027b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,10 +1582,6 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" -connect-history-api-fallback@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" - console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -1781,7 +1777,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.1, debug@^2.6.3, debug@^2.6.8, debug@^2.6.9: +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -3888,7 +3884,7 @@ kleur@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.1.tgz#7cc64b0d188d0dcbc98bdcdfdda2cc10619ddce8" -koa-compose@^3.0.0, koa-compose@^3.2.1: +koa-compose@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" dependencies: @@ -3898,10 +3894,6 @@ koa-compose@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" -koa-connect@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/koa-connect/-/koa-connect-2.0.1.tgz#2acad159c33862de1d73aa4562a48de13f137c0f" - koa-convert@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" @@ -3913,35 +3905,6 @@ koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" -koa-mount@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" - dependencies: - debug "^2.6.1" - koa-compose "^3.2.1" - -koa-range@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac" - dependencies: - stream-slice "^0.1.2" - -koa-send@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" - dependencies: - debug "^3.1.0" - http-errors "^1.6.3" - mz "^2.7.0" - resolve-path "^1.4.0" - -koa-static@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" - dependencies: - debug "^3.1.0" - koa-send "^5.0.0" - koa-webpack@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/koa-webpack/-/koa-webpack-5.1.0.tgz#7b9f04ea85c43c4d7ad845d0de01f0ed495eb5c0" @@ -4396,7 +4359,7 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -mz@^2.6.0, mz@^2.7.0: +mz@^2.6.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" dependencies: @@ -5447,7 +5410,7 @@ resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" -resolve-path@^1.3.3, resolve-path@^1.4.0: +resolve-path@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" dependencies: @@ -5827,10 +5790,6 @@ stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" -stream-slice@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" - string-length@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" From a4c8507a25d11af127b740c7a1ca79aee01ec368 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 19:02:54 +0800 Subject: [PATCH 013/135] chore: add MIT license --- LICENSE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..bc0af392f4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Endilie Yacop Sucipto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 8cbd23d6907b9447eeab207876667fe0ce5e59f0 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 29 Jul 2018 19:03:57 +0800 Subject: [PATCH 014/135] chore: remove unused package --- lib/dev.js | 19 ++-- lib/webpack/log.js | 34 ------- package.json | 3 +- yarn.lock | 233 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 233 insertions(+), 56 deletions(-) delete mode 100644 lib/webpack/log.js diff --git a/lib/dev.js b/lib/dev.js index 340f86db23..7517b23d39 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -1,17 +1,14 @@ -const ora = require('ora'); const path = require('path'); const fs = require('fs-extra'); const chalk = require('chalk'); const webpack = require('webpack'); const chokidar = require('chokidar'); const serve = require('webpack-serve'); +const webpackNiceLog = require('webpack-nicelog'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); -const blogiLog = require('./webpack/log'); module.exports = async function dev(sourceDir, cliOptions = {}) { - const logger = ora(chalk.blue('Starting development server')).start(); - // load site props from preprocessed files in source directory const props = await load(sourceDir); @@ -37,17 +34,21 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { const port = cliOptions.port || 8080; const {publicPath} = props; - config.plugin('blogi-log').use(blogiLog, [ + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ { - port, - publicPath + onDone: () => { + console.log( + `\n${chalk.blue('Development server available at ')}${chalk.cyan( + `http://localhost:${port}${publicPath}` + )}` + ); + } } ]); // create compiler from generated webpack config config = config.toConfig(); const compiler = webpack(config); - logger.succeed(); // webpack-serve await serve( @@ -56,7 +57,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { compiler, open: false, // don't open browser automatically devMiddleware: { - logLevel: 'warn', + logLevel: 'silent', publicPath }, hotClient: { diff --git a/lib/webpack/log.js b/lib/webpack/log.js deleted file mode 100644 index 1316d961b9..0000000000 --- a/lib/webpack/log.js +++ /dev/null @@ -1,34 +0,0 @@ -const chalk = require('chalk'); -const ora = require('ora'); - -function clearScreen() { - process.stdout.write('\x1Bc'); -} - -module.exports = class BlogiLog { - constructor(options) { - this.options = options; - } - - apply(compiler) { - const logger = ora(); - compiler.hooks.done.tap('blogi-log', stats => { - clearScreen(); - - const {port, publicPath} = this.options; - const time = new Date().toTimeString().match(/^[\d:]+/)[0]; - - logger.succeed( - `${chalk.gray(`[${time}]`)} Build ${chalk.green( - stats.hash.slice(0, 8) - )} finished in ${chalk.green(stats.endTime - stats.startTime)} ms!` - ); - console.log( - `\n${chalk.blue('Development server available at ')}${chalk.cyan( - `http://localhost:${port}${publicPath}` - )}` - ); - }); - compiler.hooks.invalid.tap('blogi-log', clearScreen); - } -}; diff --git a/package.json b/package.json index 823e92910e..e7cf981cd8 100644 --- a/package.json +++ b/package.json @@ -50,14 +50,13 @@ "fs-extra": "^7.0.0", "globby": "^8.0.1", "html-webpack-plugin": "^3.2.0", - "koa-convert": "^1.2.0", - "ora": "^3.0.0", "react": "^16.4.1", "react-dom": "^16.4.1", "react-router-dom": "^4.3.1", "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", + "webpack-nicelog": "^1.0.1", "webpack-serve": "^2.0.2" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 35de9027b4..3e081ced09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -267,6 +267,10 @@ acorn@^5.0.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" +address@1.0.3, address@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" + ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" @@ -404,6 +408,10 @@ array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -415,6 +423,14 @@ array-includes@^3.0.3: define-properties "^1.1.2" es-abstract "^1.7.0" +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -515,7 +531,7 @@ axobject-query@^2.0.1: dependencies: ast-types-flow "0.0.7" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@6.26.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1138,7 +1154,7 @@ boxen@^1.2.1: term-size "^1.2.0" widest-line "^2.0.0" -brace-expansion@^1.1.7: +brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: @@ -1381,7 +1397,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^1.1.3: +chalk@1.1.3, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1688,7 +1704,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@5.1.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1777,7 +1793,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.3, debug@^2.6.8, debug@^2.6.9: +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1913,6 +1929,13 @@ detect-newline@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" +detect-port-alt@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + dependencies: + address "^1.0.1" + debug "^2.6.0" + diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -2005,6 +2028,10 @@ duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + duplexify@^3.4.2, duplexify@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" @@ -2133,7 +2160,7 @@ escape-html@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2325,6 +2352,12 @@ events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" +eventsource@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" + dependencies: + original ">=0.0.5" + evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -2390,6 +2423,12 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + expect@^23.4.0: version "23.4.0" resolved "https://registry.yarnpkg.com/expect/-/expect-23.4.0.tgz#6da4ecc99c1471253e7288338983ad1ebadb60c3" @@ -2480,6 +2519,12 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +faye-websocket@~0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" @@ -2522,6 +2567,10 @@ fileset@^2.0.2: glob "^7.0.3" minimatch "^3.0.3" +filesize@3.5.11: + version "3.5.11" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.11.tgz#1919326749433bb3cf77368bd158caabcc19e9ee" + fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -2749,6 +2798,24 @@ global-dirs@^0.1.0: dependencies: ini "^1.3.4" +global-modules@1.0.0, global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + globals@^11.0.1: version "11.7.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" @@ -2804,6 +2871,12 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" +gzip-size@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520" + dependencies: + duplexer "^0.1.1" + handlebars@^4.0.3: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" @@ -2927,6 +3000,12 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -2986,6 +3065,10 @@ http-errors@^1.6.1, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-parser-js@>=0.4.0: + version "0.4.13" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -3068,7 +3151,7 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -inquirer@^3.0.6: +inquirer@3.3.0, inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: @@ -3332,6 +3415,10 @@ is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" +is-root@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-1.0.0.tgz#07b6c233bc394cd9d02ba15c966bd6660d6342d5" + is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3348,7 +3435,7 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" -is-windows@^1.0.2: +is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -3827,6 +3914,10 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -3837,6 +3928,10 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -4274,6 +4369,12 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" +minimatch@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -4656,6 +4757,12 @@ only@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" +opn@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" + dependencies: + is-wsl "^1.1.0" + opn@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" @@ -4691,6 +4798,12 @@ ora@^3.0.0: strip-ansi "^4.0.0" wcwidth "^1.0.1" +original@>=0.0.5: + version "1.0.1" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.1.tgz#b0a53ff42ba997a8c9cd1fb5daaeb42b9d693190" + dependencies: + url-parse "~1.4.0" + os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -4816,6 +4929,10 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -5075,6 +5192,10 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" +querystringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755" + quick-lru@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" @@ -5113,6 +5234,29 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dev-utils@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-5.0.1.tgz#1f396e161fe44b595db1b186a40067289bf06613" + dependencies: + address "1.0.3" + babel-code-frame "6.26.0" + chalk "1.1.3" + cross-spawn "5.1.0" + detect-port-alt "1.1.6" + escape-string-regexp "1.0.5" + filesize "3.5.11" + global-modules "1.0.0" + gzip-size "3.0.0" + inquirer "3.3.0" + is-root "1.0.0" + opn "5.2.0" + react-error-overlay "^4.0.0" + recursive-readdir "2.2.1" + shell-quote "1.6.1" + sockjs-client "1.1.4" + strip-ansi "3.0.1" + text-table "0.2.0" + react-dom@^16.4.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6" @@ -5122,6 +5266,10 @@ react-dom@^16.4.1: object-assign "^4.1.1" prop-types "^15.6.0" +react-error-overlay@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" + react-router-dom@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" @@ -5235,6 +5383,12 @@ realpath-native@^1.0.0: dependencies: util.promisify "^1.0.0" +recursive-readdir@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99" + dependencies: + minimatch "3.0.3" + redent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" @@ -5396,12 +5550,23 @@ require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" dependencies: resolve-from "^3.0.0" +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" @@ -5596,6 +5761,15 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" +shell-quote@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -5645,6 +5819,17 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +sockjs-client@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" + dependencies: + debug "^2.6.6" + eventsource "0.1.6" + faye-websocket "~0.11.0" + inherits "^2.0.1" + json3 "^3.3.2" + url-parse "^1.1.8" + source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -5822,7 +6007,7 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: +strip-ansi@3.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -5919,7 +6104,7 @@ test-exclude@^4.2.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -text-table@^0.2.0, text-table@~0.2.0: +text-table@0.2.0, text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6199,6 +6384,13 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" +url-parse@^1.1.8, url-parse@~1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.1.tgz#4dec9dad3dc8585f862fed461d2e19bbf623df30" + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -6368,6 +6560,14 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: loglevelnext "^1.0.1" uuid "^3.1.0" +webpack-nicelog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-1.0.1.tgz#64ae1a7c17c793c1edede0ea0d9540999a04dd62" + dependencies: + chalk "^2.4.1" + ora "^3.0.0" + react-dev-utils "^5.0.1" + webpack-serve@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/webpack-serve/-/webpack-serve-2.0.2.tgz#6263b7c2888e169f84105da2119079098512b404" @@ -6441,6 +6641,17 @@ webpack@^4.16.3: watchpack "^1.5.0" webpack-sources "^1.0.1" +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" @@ -6467,7 +6678,7 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@^1.2.12, which@^1.2.9, which@^1.3.0: +which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: From 7ecd4c9bef07e3ccf1fe2af461da91b8f58b055f Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 30 Jul 2018 01:35:35 +0800 Subject: [PATCH 015/135] feat: prototype blog post generation in dev server --- blog/foo/bar.md | 6 ++++++ blog/foo/baz.md | 5 +++++ lib/core/blogPost.js | 13 +++++++++++++ lib/core/index.js | 32 ++++++++++++++++---------------- lib/dev.js | 34 +++++++++++++++++++++++++++++++--- lib/loader/index.js | 9 +++++++++ lib/webpack/base.js | 10 ---------- package.json | 4 ++++ yarn.lock | 30 ++++++++++++++++++++++++++++-- 9 files changed, 112 insertions(+), 31 deletions(-) create mode 100644 blog/foo/bar.md create mode 100644 blog/foo/baz.md create mode 100644 lib/core/blogPost.js diff --git a/blog/foo/bar.md b/blog/foo/bar.md new file mode 100644 index 0000000000..4b28a826e3 --- /dev/null +++ b/blog/foo/bar.md @@ -0,0 +1,6 @@ +--- +title: Lorem ipsum +date: 2018-06-20 +--- + +Lorem ipsumsdsdsad diff --git a/blog/foo/baz.md b/blog/foo/baz.md new file mode 100644 index 0000000000..c4e0cbf40d --- /dev/null +++ b/blog/foo/baz.md @@ -0,0 +1,5 @@ +--- +title: Baz +date: 2018-05-20 +--- +Life is so good diff --git a/lib/core/blogPost.js b/lib/core/blogPost.js new file mode 100644 index 0000000000..d3611ade2f --- /dev/null +++ b/lib/core/blogPost.js @@ -0,0 +1,13 @@ +const React = require('react'); +import blogDatas from '@generated/blogDatas'; + +// inner blog component for the article itself, without sidebar/header/footer +class BlogPost extends React.Component { + render() { + const {match} = this.props; + const post = blogDatas.find(blog => blog.path === match.path); + return
{post && post.content}
; + } +} + +module.exports = BlogPost; diff --git a/lib/core/index.js b/lib/core/index.js index dbe96b255c..2a4a5fc3ed 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -1,30 +1,30 @@ import React from 'react'; import {render} from 'react-dom'; -import {BrowserRouter, Route, Switch} from 'react-router-dom'; -import Hello from '@theme/hello'; -import Layout from '@theme/layout'; +import {BrowserRouter, Route, Switch, Link} from 'react-router-dom'; +import BlogPost from './blogPost'; +import blogDatas from '@generated/blogDatas'; class App extends React.Component { render() { - const routes = [ - { - path: '/', - component: Hello - }, - { - path: '/layout', - component: Layout - } - ]; - return (
- {routes.map(({path, component}) => ( - + {blogDatas.map(({path}) => ( + ))} +
+ {blogDatas.map(({path}) => { + return ( +
+ + {path} + +
+ ); + })} +
); diff --git a/lib/dev.js b/lib/dev.js index 7517b23d39..949048b135 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -3,11 +3,22 @@ const fs = require('fs-extra'); const chalk = require('chalk'); const webpack = require('webpack'); const chokidar = require('chokidar'); +const convert = require('koa-connect') +const range = require('koa-range') +const history = require('connect-history-api-fallback') +const portfinder = require('portfinder') const serve = require('webpack-serve'); const webpackNiceLog = require('webpack-nicelog'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); +async function getPort (port) { + portfinder.basePort = parseInt(port) || 8080 + port = await portfinder.getPortPromise() + return port +} + module.exports = async function dev(sourceDir, cliOptions = {}) { // load site props from preprocessed files in source directory const props = await load(sourceDir); @@ -18,7 +29,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { console.error(chalk.red(err.stack)); }); }; - const fsWatcher = chokidar.watch(['**/*.md'], { + const fsWatcher = chokidar.watch(['**/*.md', '.blogi/config.js'], { cwd: sourceDir, ignoreInitial: true }); @@ -31,7 +42,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // resolve webpack config let config = createDevConfig(props); - const port = cliOptions.port || 8080; + const port = await getPort(cliOptions.port); const {publicPath} = props; config.plugin('WebpackNiceLog').use(webpackNiceLog, [ @@ -46,6 +57,15 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { } ]); + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + inject: false, + hash: true, + template: path.resolve(__dirname, 'core/index.html'), + filename: 'index.html' + } + ]); + // create compiler from generated webpack config config = config.toConfig(); const compiler = webpack(config); @@ -65,7 +85,15 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { logLevel: 'error' }, logLevel: 'error', - port + port, + add: app => { + app.use(range) // enable range request https://tools.ietf.org/html/rfc7233 + app.use(convert(history({ + rewrites: [ + { from: /\.html$/, to: '/' } + ] + }))) + } } ); }; diff --git a/lib/loader/index.js b/lib/loader/index.js index a808bf23dc..274c06f206 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -10,6 +10,15 @@ module.exports = async function load(sourceDir) { // extract data from all blog files const blogDatas = await loadBlog(sourceDir); + fs.writeFile( + path.resolve(__dirname, '../generated/blogDatas.js'), + `${'/**\n' + + ' * @' + + 'generated\n' + + ' */\n' + + 'module.exports = '}${JSON.stringify(blogDatas, null, 2)};\n` + ); + // resolve outDir const outDir = siteConfig.dest ? path.resolve(siteConfig.dest) diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 995f7f22de..9133a9ff7d 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -1,6 +1,5 @@ const Config = require('webpack-chain'); const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = function createBaseConfig(props) { const {outDir, themePath, sourceDir, publicPath} = props; @@ -43,14 +42,5 @@ module.exports = function createBaseConfig(props) { presets: ['env', 'react'] }); - config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ - { - inject: false, - hash: true, - template: path.resolve(__dirname, '../core/index.html'), - filename: 'index.html' - } - ]); - return config; }; diff --git a/package.json b/package.json index e7cf981cd8..933d0467ed 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,14 @@ "chalk": "^2.4.1", "chokidar": "^2.0.4", "commander": "^2.16.0", + "connect-history-api-fallback": "^1.5.0", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", "html-webpack-plugin": "^3.2.0", + "koa-connect": "^2.0.1", + "koa-range": "^0.3.0", + "portfinder": "^1.0.13", "react": "^16.4.1", "react-dom": "^16.4.1", "react-router-dom": "^4.3.1", diff --git a/yarn.lock b/yarn.lock index 3e081ced09..045cd34d26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -499,7 +499,7 @@ async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" -async@^1.4.0: +async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -1598,6 +1598,10 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +connect-history-api-fallback@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -3989,6 +3993,10 @@ koa-compose@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" +koa-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/koa-connect/-/koa-connect-2.0.1.tgz#2acad159c33862de1d73aa4562a48de13f137c0f" + koa-convert@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" @@ -4000,6 +4008,12 @@ koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" +koa-range@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac" + dependencies: + stream-slice "^0.1.2" + koa-webpack@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/koa-webpack/-/koa-webpack-5.1.0.tgz#7b9f04ea85c43c4d7ad845d0de01f0ed495eb5c0" @@ -4435,7 +4449,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: +mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -5057,6 +5071,14 @@ pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" +portfinder@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -5975,6 +5997,10 @@ stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" +stream-slice@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" + string-length@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" From 12cded5fa0123dd278dfa43942f7b589dd4dce11 Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 30 Jul 2018 14:20:03 +0800 Subject: [PATCH 016/135] refactor: config path --- blog/{.blogi => }/config.js | 0 lib/loader/config.js | 2 +- test/loader/__fixtures__/custom/{.blogi => }/config.js | 0 test/loader/__fixtures__/simple/{.blogi => }/config.js | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename blog/{.blogi => }/config.js (100%) rename test/loader/__fixtures__/custom/{.blogi => }/config.js (100%) rename test/loader/__fixtures__/simple/{.blogi => }/config.js (100%) diff --git a/blog/.blogi/config.js b/blog/config.js similarity index 100% rename from blog/.blogi/config.js rename to blog/config.js diff --git a/lib/loader/config.js b/lib/loader/config.js index 38fd0201f9..fcdcbef3d1 100644 --- a/lib/loader/config.js +++ b/lib/loader/config.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); module.exports = function loadConfig(sourceDir, deleteCache = true) { - const configPath = path.resolve(sourceDir, '.blogi', 'config.js'); + const configPath = path.resolve(sourceDir, 'config.js'); if (deleteCache) { delete require.cache[configPath]; } diff --git a/test/loader/__fixtures__/custom/.blogi/config.js b/test/loader/__fixtures__/custom/config.js similarity index 100% rename from test/loader/__fixtures__/custom/.blogi/config.js rename to test/loader/__fixtures__/custom/config.js diff --git a/test/loader/__fixtures__/simple/.blogi/config.js b/test/loader/__fixtures__/simple/config.js similarity index 100% rename from test/loader/__fixtures__/simple/.blogi/config.js rename to test/loader/__fixtures__/simple/config.js From f7f063c56e026790735020a37535c8f037cd003b Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 30 Jul 2018 15:23:28 +0800 Subject: [PATCH 017/135] feat: add more koa app for webpack-serve add-on --- lib/dev.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/dev.js b/lib/dev.js index 949048b135..c0975f7f83 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -3,20 +3,20 @@ const fs = require('fs-extra'); const chalk = require('chalk'); const webpack = require('webpack'); const chokidar = require('chokidar'); -const convert = require('koa-connect') -const range = require('koa-range') -const history = require('connect-history-api-fallback') -const portfinder = require('portfinder') +const convert = require('koa-connect'); +const range = require('koa-range'); +const history = require('connect-history-api-fallback'); +const portfinder = require('portfinder'); const serve = require('webpack-serve'); const webpackNiceLog = require('webpack-nicelog'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); -async function getPort (port) { - portfinder.basePort = parseInt(port) || 8080 - port = await portfinder.getPortPromise() - return port +async function getPort(port) { + portfinder.basePort = parseInt(port) || 8080; + port = await portfinder.getPortPromise(); + return port; } module.exports = async function dev(sourceDir, cliOptions = {}) { @@ -87,13 +87,16 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { logLevel: 'error', port, add: app => { - app.use(range) // enable range request https://tools.ietf.org/html/rfc7233 - app.use(convert(history({ - rewrites: [ - { from: /\.html$/, to: '/' } - ] - }))) + app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 + app.use( + convert( + history({ + rewrites: [{from: /\.html$/, to: '/'}] + }) + ) + ); } } ); + console.log("finish serve"); }; From a80399631fe256a0374b91f754362d399463392c Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 30 Jul 2018 15:23:56 +0800 Subject: [PATCH 018/135] refactor: use cache for blogDatas generation --- lib/core/index.js | 4 ++-- lib/helpers/generate.js | 14 ++++++++++++++ lib/helpers/index.js | 1 + lib/loader/index.js | 15 ++++++++------- 4 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 lib/helpers/generate.js create mode 100644 lib/helpers/index.js diff --git a/lib/core/index.js b/lib/core/index.js index 2a4a5fc3ed..5f95439fb0 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -17,8 +17,8 @@ class App extends React.Component {
{blogDatas.map(({path}) => { return ( -
- +
+ {path}
diff --git a/lib/helpers/generate.js b/lib/helpers/generate.js new file mode 100644 index 0000000000..12444b7888 --- /dev/null +++ b/lib/helpers/generate.js @@ -0,0 +1,14 @@ +const path = require('path'); +const fs = require('fs-extra'); + +const genPath = path.resolve(__dirname, '../generated'); +fs.ensureDirSync(genPath); + +const genCache = new Map(); +module.exports = async function(file, content) { + const cached = genCache.get(file); + if (cached !== content) { + await fs.writeFile(path.join(genPath, file), content); + genCache.set(file, content); + } +}; diff --git a/lib/helpers/index.js b/lib/helpers/index.js new file mode 100644 index 0000000000..0c43e95b1d --- /dev/null +++ b/lib/helpers/index.js @@ -0,0 +1 @@ +exports.generate = require('./generate'); diff --git a/lib/loader/index.js b/lib/loader/index.js index 274c06f206..90354de39d 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -2,6 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); const loadBlog = require('./blog'); +const {generate} = require('../helpers'); module.exports = async function load(sourceDir) { // load siteConfig @@ -10,13 +11,13 @@ module.exports = async function load(sourceDir) { // extract data from all blog files const blogDatas = await loadBlog(sourceDir); - fs.writeFile( - path.resolve(__dirname, '../generated/blogDatas.js'), - `${'/**\n' + - ' * @' + - 'generated\n' + - ' */\n' + - 'module.exports = '}${JSON.stringify(blogDatas, null, 2)};\n` + await generate( + 'blogDatas.js', + `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( + blogDatas, + null, + 2 + )};\n` ); // resolve outDir From dd5757ce65673781cbef5e36cde3af92a126307f Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 30 Jul 2018 15:50:48 +0800 Subject: [PATCH 019/135] chore: prettier & remove unused --- lib/core/blogPost.js | 2 +- lib/core/index.js | 4 +--- lib/dev.js | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/core/blogPost.js b/lib/core/blogPost.js index d3611ade2f..bc02cbfdc1 100644 --- a/lib/core/blogPost.js +++ b/lib/core/blogPost.js @@ -1,4 +1,4 @@ -const React = require('react'); +import React from 'react'; import blogDatas from '@generated/blogDatas'; // inner blog component for the article itself, without sidebar/header/footer diff --git a/lib/core/index.js b/lib/core/index.js index 5f95439fb0..fcda46fd90 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -18,9 +18,7 @@ class App extends React.Component { {blogDatas.map(({path}) => { return (
- - {path} - + {path}
); })} diff --git a/lib/dev.js b/lib/dev.js index c0975f7f83..4810e52e5f 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -98,5 +98,4 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { } } ); - console.log("finish serve"); }; From c5dfddaf619fb42e2362baf7b3e30cd19905d083 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 15:52:20 +0800 Subject: [PATCH 020/135] chore: refactor & fix typo --- {blog => examples}/config.js | 0 {blog => examples}/foo/bar.md | 0 {blog => examples}/foo/baz.md | 0 {blog => examples}/hello-world.md | 0 lib/dev.js | 2 +- package.json | 4 ++-- 6 files changed, 3 insertions(+), 3 deletions(-) rename {blog => examples}/config.js (100%) rename {blog => examples}/foo/bar.md (100%) rename {blog => examples}/foo/baz.md (100%) rename {blog => examples}/hello-world.md (100%) diff --git a/blog/config.js b/examples/config.js similarity index 100% rename from blog/config.js rename to examples/config.js diff --git a/blog/foo/bar.md b/examples/foo/bar.md similarity index 100% rename from blog/foo/bar.md rename to examples/foo/bar.md diff --git a/blog/foo/baz.md b/examples/foo/baz.md similarity index 100% rename from blog/foo/baz.md rename to examples/foo/baz.md diff --git a/blog/hello-world.md b/examples/hello-world.md similarity index 100% rename from blog/hello-world.md rename to examples/hello-world.md diff --git a/lib/dev.js b/lib/dev.js index 4810e52e5f..589b6380a0 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -29,7 +29,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { console.error(chalk.red(err.stack)); }); }; - const fsWatcher = chokidar.watch(['**/*.md', '.blogi/config.js'], { + const fsWatcher = chokidar.watch(['**/*.md', 'config.js'], { cwd: sourceDir, ignoreInitial: true }); diff --git a/package.json b/package.json index 933d0467ed..bf3a75fd8a 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "blogi": "bin/blogi.js" }, "scripts": { - "dev": "node bin/blogi dev blog", - "build": "node bin/blogi build blog", + "dev": "node bin/blogi dev examples", + "build": "node bin/blogi build examples", "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "test": "jest" From 0c69604fb25b2f1e9785927853060dde412a688c Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 16:06:52 +0800 Subject: [PATCH 021/135] feat: add koa-static to serve static files --- examples/hello-world.md | 2 +- lib/dev.js | 12 +++++++++--- package.json | 1 + yarn.lock | 20 ++++++++++++++++++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/hello-world.md b/examples/hello-world.md index 1dbbb2e3c2..451588e4c7 100644 --- a/examples/hello-world.md +++ b/examples/hello-world.md @@ -9,4 +9,4 @@ Hi, Endilie here. -Random thoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. +Random tsasshoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. diff --git a/lib/dev.js b/lib/dev.js index 589b6380a0..397ef14b0c 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -5,6 +5,7 @@ const webpack = require('webpack'); const chokidar = require('chokidar'); const convert = require('koa-connect'); const range = require('koa-range'); +const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); @@ -71,14 +72,15 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { const compiler = webpack(config); // webpack-serve + const nonExistentDir = path.resolve(__dirname, 'non-existent') await serve( {}, { + content: [nonExistentDir], compiler, - open: false, // don't open browser automatically + open: true, devMiddleware: { - logLevel: 'silent', - publicPath + logLevel: 'silent' }, hotClient: { port: port + 1, @@ -87,6 +89,10 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { logLevel: 'error', port, add: app => { + const staticDir = path.resolve(sourceDir, 'public'); + if (fs.existsSync(staticDir)) { + app.use(mount(publicPath, serveStatic(staticDir))); + } app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 app.use( convert( diff --git a/package.json b/package.json index bf3a75fd8a..58f6f1b753 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "html-webpack-plugin": "^3.2.0", "koa-connect": "^2.0.1", "koa-range": "^0.3.0", + "koa-static": "^5.0.0", "portfinder": "^1.0.13", "react": "^16.4.1", "react-dom": "^16.4.1", diff --git a/yarn.lock b/yarn.lock index 045cd34d26..9077bb1170 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4014,6 +4014,22 @@ koa-range@^0.3.0: dependencies: stream-slice "^0.1.2" +koa-send@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" + dependencies: + debug "^3.1.0" + http-errors "^1.6.3" + mz "^2.7.0" + resolve-path "^1.4.0" + +koa-static@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" + dependencies: + debug "^3.1.0" + koa-send "^5.0.0" + koa-webpack@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/koa-webpack/-/koa-webpack-5.1.0.tgz#7b9f04ea85c43c4d7ad845d0de01f0ed495eb5c0" @@ -4474,7 +4490,7 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -mz@^2.6.0: +mz@^2.6.0, mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" dependencies: @@ -5597,7 +5613,7 @@ resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" -resolve-path@^1.3.3: +resolve-path@^1.3.3, resolve-path@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" dependencies: From 82be417197659aa362d543942aa04f774f6e271f Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 16:08:55 +0800 Subject: [PATCH 022/135] chore: namespace webpack output --- lib/webpack/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 9133a9ff7d..af846cfc04 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -10,7 +10,7 @@ module.exports = function createBaseConfig(props) { config .mode(isProd ? 'production' : 'development') .output.path(outDir) - .filename(isProd ? '[name].[chunkhash].js' : '[name].js') + .filename(isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js') .publicPath(isProd ? publicPath : '/'); config.resolve From d9a86a54c116825088a0c101c24334e6d2ee5d9b Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 16:18:52 +0800 Subject: [PATCH 023/135] feat & refactor: webpack-serve-waitpage and lint --- lib/core/blogPost.js | 26 ++++++++++----------- lib/core/index.js | 14 +++++------- lib/dev.js | 12 ++++++---- lib/helpers/generate.js | 28 +++++++++++------------ lib/webpack/base.js | 4 +++- package.json | 4 +++- test/loader/__fixtures__/custom/config.js | 12 +++++----- test/loader/__fixtures__/simple/config.js | 8 +++---- yarn.lock | 21 +++++++++++++++-- 9 files changed, 75 insertions(+), 54 deletions(-) diff --git a/lib/core/blogPost.js b/lib/core/blogPost.js index bc02cbfdc1..0698cf6581 100644 --- a/lib/core/blogPost.js +++ b/lib/core/blogPost.js @@ -1,13 +1,13 @@ -import React from 'react'; -import blogDatas from '@generated/blogDatas'; - -// inner blog component for the article itself, without sidebar/header/footer -class BlogPost extends React.Component { - render() { - const {match} = this.props; - const post = blogDatas.find(blog => blog.path === match.path); - return
{post && post.content}
; - } -} - -module.exports = BlogPost; +import React from 'react'; +import blogDatas from '@generated/blogDatas'; + +// inner blog component for the article itself, without sidebar/header/footer +class BlogPost extends React.Component { + render() { + const {match} = this.props; + const post = blogDatas.find(blog => blog.path === match.path); + return
{post && post.content}
; + } +} + +module.exports = BlogPost; diff --git a/lib/core/index.js b/lib/core/index.js index fcda46fd90..548beeb1d6 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -1,8 +1,8 @@ import React from 'react'; import {render} from 'react-dom'; import {BrowserRouter, Route, Switch, Link} from 'react-router-dom'; -import BlogPost from './blogPost'; import blogDatas from '@generated/blogDatas'; +import BlogPost from './blogPost'; class App extends React.Component { render() { @@ -15,13 +15,11 @@ class App extends React.Component { ))}
- {blogDatas.map(({path}) => { - return ( -
- {path} -
- ); - })} + {blogDatas.map(({path}) => ( +
+ {path} +
+ ))}
diff --git a/lib/dev.js b/lib/dev.js index 397ef14b0c..73e0745904 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -5,19 +5,20 @@ const webpack = require('webpack'); const chokidar = require('chokidar'); const convert = require('koa-connect'); const range = require('koa-range'); +const mount = require('koa-mount'); const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); +const serveWaitpage = require('webpack-serve-waitpage'); const webpackNiceLog = require('webpack-nicelog'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('./loader'); const createDevConfig = require('./webpack/dev'); async function getPort(port) { - portfinder.basePort = parseInt(port) || 8080; - port = await portfinder.getPortPromise(); - return port; + portfinder.basePort = parseInt(port, 10) || 8080; + return await portfinder.getPortPromise(); } module.exports = async function dev(sourceDir, cliOptions = {}) { @@ -72,7 +73,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { const compiler = webpack(config); // webpack-serve - const nonExistentDir = path.resolve(__dirname, 'non-existent') + const nonExistentDir = path.resolve(__dirname, 'non-existent'); await serve( {}, { @@ -88,11 +89,12 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { }, logLevel: 'error', port, - add: app => { + add: (app, middleware, options) => { const staticDir = path.resolve(sourceDir, 'public'); if (fs.existsSync(staticDir)) { app.use(mount(publicPath, serveStatic(staticDir))); } + app.use(serveWaitpage(options, {theme: 'dark'})); // https://github.com/elisherer/webpack-serve-waitpage#middleware-options app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 app.use( convert( diff --git a/lib/helpers/generate.js b/lib/helpers/generate.js index 12444b7888..6b0550da01 100644 --- a/lib/helpers/generate.js +++ b/lib/helpers/generate.js @@ -1,14 +1,14 @@ -const path = require('path'); -const fs = require('fs-extra'); - -const genPath = path.resolve(__dirname, '../generated'); -fs.ensureDirSync(genPath); - -const genCache = new Map(); -module.exports = async function(file, content) { - const cached = genCache.get(file); - if (cached !== content) { - await fs.writeFile(path.join(genPath, file), content); - genCache.set(file, content); - } -}; +const path = require('path'); +const fs = require('fs-extra'); + +const genPath = path.resolve(__dirname, '../generated'); +fs.ensureDirSync(genPath); + +const genCache = new Map(); +module.exports = async function(file, content) { + const cached = genCache.get(file); + if (cached !== content) { + await fs.writeFile(path.join(genPath, file), content); + genCache.set(file, content); + } +}; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index af846cfc04..069a6de38f 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -10,7 +10,9 @@ module.exports = function createBaseConfig(props) { config .mode(isProd ? 'production' : 'development') .output.path(outDir) - .filename(isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js') + .filename( + isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' + ) .publicPath(isProd ? publicPath : '/'); config.resolve diff --git a/package.json b/package.json index 58f6f1b753..609f7d157e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "globby": "^8.0.1", "html-webpack-plugin": "^3.2.0", "koa-connect": "^2.0.1", + "koa-mount": "^3.0.0", "koa-range": "^0.3.0", "koa-static": "^5.0.0", "portfinder": "^1.0.13", @@ -62,7 +63,8 @@ "webpack": "^4.16.3", "webpack-chain": "^4.8.0", "webpack-nicelog": "^1.0.1", - "webpack-serve": "^2.0.2" + "webpack-serve": "^2.0.2", + "webpack-serve-waitpage": "^1.0.1" }, "engines": { "node": ">=8" diff --git a/test/loader/__fixtures__/custom/config.js b/test/loader/__fixtures__/custom/config.js index 8897ce391c..0c4661619e 100644 --- a/test/loader/__fixtures__/custom/config.js +++ b/test/loader/__fixtures__/custom/config.js @@ -1,6 +1,6 @@ -module.exports = { - title: 'Hello World', - description: 'Hello World', - dest: 'blogi', - base: 'blogi' -}; +module.exports = { + title: 'Hello World', + description: 'Hello World', + dest: 'blogi', + base: 'blogi' +}; diff --git a/test/loader/__fixtures__/simple/config.js b/test/loader/__fixtures__/simple/config.js index 14da102249..22d383d3c4 100644 --- a/test/loader/__fixtures__/simple/config.js +++ b/test/loader/__fixtures__/simple/config.js @@ -1,4 +1,4 @@ -module.exports = { - title: 'Hello World', - description: 'Hello World' -}; +module.exports = { + title: 'Hello World', + description: 'Hello World' +}; diff --git a/yarn.lock b/yarn.lock index 9077bb1170..52e0357881 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1797,7 +1797,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2055,6 +2055,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +ejs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" @@ -3983,7 +3987,7 @@ kleur@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.1.tgz#7cc64b0d188d0dcbc98bdcdfdda2cc10619ddce8" -koa-compose@^3.0.0: +koa-compose@^3.0.0, koa-compose@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" dependencies: @@ -4008,6 +4012,13 @@ koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" +koa-mount@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" + dependencies: + debug "^2.6.1" + koa-compose "^3.2.1" + koa-range@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac" @@ -6610,6 +6621,12 @@ webpack-nicelog@^1.0.1: ora "^3.0.0" react-dev-utils "^5.0.1" +webpack-serve-waitpage@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/webpack-serve-waitpage/-/webpack-serve-waitpage-1.0.1.tgz#8aee5bf8aafcf997c72a74fc48ae1c495001fde9" + dependencies: + ejs "^2.6.1" + webpack-serve@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/webpack-serve/-/webpack-serve-2.0.2.tgz#6263b7c2888e169f84105da2119079098512b404" From 9070fb50ab9ac5b20f73b3fb6e4f2f1ad6c6e3f5 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 16:33:38 +0800 Subject: [PATCH 024/135] refactor: dev --- lib/dev.js | 216 ++++++++++++++++++++++----------------------- lib/webpack/dev.js | 20 ++--- 2 files changed, 117 insertions(+), 119 deletions(-) diff --git a/lib/dev.js b/lib/dev.js index 73e0745904..e3fd9f4d5d 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -1,109 +1,107 @@ -const path = require('path'); -const fs = require('fs-extra'); -const chalk = require('chalk'); -const webpack = require('webpack'); -const chokidar = require('chokidar'); -const convert = require('koa-connect'); -const range = require('koa-range'); -const mount = require('koa-mount'); -const serveStatic = require('koa-static'); -const history = require('connect-history-api-fallback'); -const portfinder = require('portfinder'); -const serve = require('webpack-serve'); -const serveWaitpage = require('webpack-serve-waitpage'); -const webpackNiceLog = require('webpack-nicelog'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const load = require('./loader'); -const createDevConfig = require('./webpack/dev'); - -async function getPort(port) { - portfinder.basePort = parseInt(port, 10) || 8080; - return await portfinder.getPortPromise(); -} - -module.exports = async function dev(sourceDir, cliOptions = {}) { - // load site props from preprocessed files in source directory - const props = await load(sourceDir); - - // Reload for any add/change/remove of file - const reload = () => { - load(sourceDir).catch(err => { - console.error(chalk.red(err.stack)); - }); - }; - const fsWatcher = chokidar.watch(['**/*.md', 'config.js'], { - cwd: sourceDir, - ignoreInitial: true - }); - fsWatcher.on('add', reload); - fsWatcher.on('change', reload); - fsWatcher.on('unlink', reload); - fsWatcher.on('addDir', reload); - fsWatcher.on('unlinkDir', reload); - - // resolve webpack config - let config = createDevConfig(props); - - const port = await getPort(cliOptions.port); - const {publicPath} = props; - - config.plugin('WebpackNiceLog').use(webpackNiceLog, [ - { - onDone: () => { - console.log( - `\n${chalk.blue('Development server available at ')}${chalk.cyan( - `http://localhost:${port}${publicPath}` - )}` - ); - } - } - ]); - - config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ - { - inject: false, - hash: true, - template: path.resolve(__dirname, 'core/index.html'), - filename: 'index.html' - } - ]); - - // create compiler from generated webpack config - config = config.toConfig(); - const compiler = webpack(config); - - // webpack-serve - const nonExistentDir = path.resolve(__dirname, 'non-existent'); - await serve( - {}, - { - content: [nonExistentDir], - compiler, - open: true, - devMiddleware: { - logLevel: 'silent' - }, - hotClient: { - port: port + 1, - logLevel: 'error' - }, - logLevel: 'error', - port, - add: (app, middleware, options) => { - const staticDir = path.resolve(sourceDir, 'public'); - if (fs.existsSync(staticDir)) { - app.use(mount(publicPath, serveStatic(staticDir))); - } - app.use(serveWaitpage(options, {theme: 'dark'})); // https://github.com/elisherer/webpack-serve-waitpage#middleware-options - app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 - app.use( - convert( - history({ - rewrites: [{from: /\.html$/, to: '/'}] - }) - ) - ); - } - } - ); -}; +const path = require('path'); +const fs = require('fs-extra'); +const chalk = require('chalk'); +const webpack = require('webpack'); +const chokidar = require('chokidar'); +const convert = require('koa-connect'); +const range = require('koa-range'); +const mount = require('koa-mount'); +const serveStatic = require('koa-static'); +const history = require('connect-history-api-fallback'); +const portfinder = require('portfinder'); +const serve = require('webpack-serve'); +const serveWaitpage = require('webpack-serve-waitpage'); +const webpackNiceLog = require('webpack-nicelog'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const load = require('./loader'); +const createDevConfig = require('./webpack/dev'); + +async function getPort(port) { + portfinder.basePort = parseInt(port, 10) || 8080; + return await portfinder.getPortPromise(); +} + +module.exports = async function dev(sourceDir, cliOptions = {}) { + // load site props from preprocessed files in source directory + const props = await load(sourceDir); + + // Reload for any add/change/remove of file + const reload = () => { + load(sourceDir).catch(err => { + console.error(chalk.red(err.stack)); + }); + }; + const fsWatcher = chokidar.watch(['**/*.md', 'config.js'], { + cwd: sourceDir, + ignoreInitial: true + }); + fsWatcher.on('add', reload); + fsWatcher.on('change', reload); + fsWatcher.on('unlink', reload); + fsWatcher.on('addDir', reload); + fsWatcher.on('unlinkDir', reload); + + const port = await getPort(cliOptions.port); + const {publicPath} = props; + + // resolve webpack config + let config = createDevConfig(props); + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ + { + onDone: () => { + console.log( + `\n${chalk.blue('Development server available at ')}${chalk.cyan( + `http://localhost:${port}${publicPath}` + )}` + ); + } + } + ]); + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + inject: false, + hash: true, + template: path.resolve(__dirname, 'core/index.html'), + filename: 'index.html' + } + ]); + + // create compiler from generated webpack config + config = config.toConfig(); + const compiler = webpack(config); + + // webpack-serve + const nonExistentDir = path.resolve(__dirname, 'non-existent'); + await serve( + {}, + { + content: [nonExistentDir], + compiler, + open: true, + devMiddleware: { + logLevel: 'silent' + }, + hotClient: { + port: port + 1, + logLevel: 'error' + }, + logLevel: 'error', + port, + add: (app, middleware, options) => { + const staticDir = path.resolve(sourceDir, 'public'); + if (fs.existsSync(staticDir)) { + app.use(mount(publicPath, serveStatic(staticDir))); + } + app.use(serveWaitpage(options, {theme: 'dark'})); // https://github.com/elisherer/webpack-serve-waitpage#middleware-options + app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 + app.use( + convert( + history({ + rewrites: [{from: /\.html$/, to: '/'}] + }) + ) + ); + } + } + ); +}; diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js index 6b420c559c..8a2e5cd182 100644 --- a/lib/webpack/dev.js +++ b/lib/webpack/dev.js @@ -1,10 +1,10 @@ -const path = require('path'); -const createBaseConfig = require('./base'); - -module.exports = function createDevConfig(props) { - const config = createBaseConfig(props); - - config.entry('main').add(path.resolve(__dirname, '../core/index.js')); - - return config; -}; +const path = require('path'); +const createBaseConfig = require('./base'); + +module.exports = function createDevConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/index.js')); + + return config; +}; From dbf78c5c14a8bbfe5472a5353e7d27d8bda13443 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 16:55:53 +0800 Subject: [PATCH 025/135] refactor: folder structure & filename --- bin/blogi.js | 116 ++++++++++++++--------------- lib/{ => commands}/build.js | 0 lib/{ => commands}/dev.js | 6 +- lib/core/{index.js => devEntry.js} | 2 +- lib/index.js | 9 ++- lib/loader/index.js | 14 ++-- lib/{theme => ui}/hello.js | 0 lib/{theme => ui}/layout.js | 0 lib/webpack/base.js | 4 +- lib/webpack/dev.js | 2 +- 10 files changed, 79 insertions(+), 74 deletions(-) rename lib/{ => commands}/build.js (100%) rename lib/{ => commands}/dev.js (92%) rename lib/core/{index.js => devEntry.js} (97%) rename lib/{theme => ui}/hello.js (100%) rename lib/{theme => ui}/layout.js (100%) diff --git a/bin/blogi.js b/bin/blogi.js index c9fd9746ac..e58c5861ef 100644 --- a/bin/blogi.js +++ b/bin/blogi.js @@ -1,58 +1,58 @@ -#!/usr/bin/env node - -const chalk = require('chalk'); -const semver = require('semver'); -const path = require('path'); -const program = require('commander'); -const {dev, build} = require('../lib'); -const requiredVersion = require('../package.json').engines.node; - -if (!semver.satisfies(process.version, requiredVersion)) { - console.log( - chalk.red(`\nMinimum node version not met :)`) + - chalk.yellow( - `\nYou are using Node ${ - process.version - }, but blogi requires Node ${requiredVersion}.\n` - ) - ); - process.exit(1); -} - -function wrapCommand(fn) { - return (...args) => - fn(...args).catch(err => { - console.error(chalk.red(err.stack)); - process.exitCode = 1; - }); -} - -program - .version(require('../package.json').version) - .usage(' [options]'); - -program - .command('dev [targetDir]') - .description('start development server') - .option('-p, --port ', 'use specified port (default: 8080)') - .action((dir = '.', {port}) => { - wrapCommand(dev)(path.resolve(dir), {port}); - }); - -program - .command('build [targetDir]') - .description('build dir as static site') - .option( - '-d, --dest ', - 'specify build output dir (default: .blogi/dist)' - ) - .action((dir = '.', {dest}) => { - const outDir = dest ? path.resolve(dest) : null; - wrapCommand(build)(path.resolve(dir), {outDir}); - }); - -program.parse(process.argv); - -if (!process.argv.slice(2).length) { - program.outputHelp(); -} +#!/usr/bin/env node + +const chalk = require('chalk'); +const semver = require('semver'); +const path = require('path'); +const program = require('commander'); +const {dev, build} = require('../lib'); +const requiredVersion = require('../package.json').engines.node; + +if (!semver.satisfies(process.version, requiredVersion)) { + console.log( + chalk.red(`\nMinimum node version not met :)`) + + chalk.yellow( + `\nYou are using Node ${ + process.version + }, but blogi requires Node ${requiredVersion}.\n` + ) + ); + process.exit(1); +} + +function wrapCommand(fn) { + return (...args) => + fn(...args).catch(err => { + console.error(chalk.red(err.stack)); + process.exitCode = 1; + }); +} + +program + .version(require('../package.json').version) + .usage(' [options]'); + +program + .command('dev [targetDir]') + .description('start development server') + .option('-p, --port ', 'use specified port (default: 8080)') + .action((dir = '.', {port}) => { + wrapCommand(dev)(path.resolve(dir), {port}); + }); + +program + .command('build [targetDir]') + .description('build dir as static site') + .option( + '-d, --dest ', + 'specify build output dir (default: .blogi/dist)' + ) + .action((dir = '.', {dest}) => { + const outDir = dest ? path.resolve(dest) : null; + wrapCommand(build)(path.resolve(dir), {outDir}); + }); + +program.parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp(); +} diff --git a/lib/build.js b/lib/commands/build.js similarity index 100% rename from lib/build.js rename to lib/commands/build.js diff --git a/lib/dev.js b/lib/commands/dev.js similarity index 92% rename from lib/dev.js rename to lib/commands/dev.js index e3fd9f4d5d..dd3b0ec62e 100644 --- a/lib/dev.js +++ b/lib/commands/dev.js @@ -13,8 +13,8 @@ const serve = require('webpack-serve'); const serveWaitpage = require('webpack-serve-waitpage'); const webpackNiceLog = require('webpack-nicelog'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const load = require('./loader'); -const createDevConfig = require('./webpack/dev'); +const load = require('../loader'); +const createDevConfig = require('../webpack/dev'); async function getPort(port) { portfinder.basePort = parseInt(port, 10) || 8080; @@ -61,7 +61,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { { inject: false, hash: true, - template: path.resolve(__dirname, 'core/index.html'), + template: path.resolve(__dirname, '../core/index.html'), filename: 'index.html' } ]); diff --git a/lib/core/index.js b/lib/core/devEntry.js similarity index 97% rename from lib/core/index.js rename to lib/core/devEntry.js index 548beeb1d6..8fb024c577 100644 --- a/lib/core/index.js +++ b/lib/core/devEntry.js @@ -19,7 +19,7 @@ class App extends React.Component {
{path}
- ))} + ))}
diff --git a/lib/index.js b/lib/index.js index 689d88721c..025145a775 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,2 +1,7 @@ -exports.dev = require('./dev'); -exports.build = require('./build'); +const dev = require('./commands/dev'); +const build = require('./commands/build'); + +module.exports = { + dev, + build +}; diff --git a/lib/loader/index.js b/lib/loader/index.js index 90354de39d..f6e69ab56a 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -25,12 +25,12 @@ module.exports = async function load(sourceDir) { ? path.resolve(siteConfig.dest) : path.resolve(sourceDir, '.blogi/dist'); - // resolve the path of our app theme/ layout - const themePath = - !siteConfig.themePath || - !fs.existsSync(path.resolve(sourceDir, siteConfig.themePath)) - ? path.resolve(__dirname, '../theme') - : siteConfig.themePath; + // resolve the path of our app user interface layout + const uiPath = + !siteConfig.uiPath || + !fs.existsSync(path.resolve(sourceDir, siteConfig.uiPath)) + ? path.resolve(__dirname, '../ui') + : siteConfig.uiPath; const publicPath = siteConfig.base || '/'; @@ -39,7 +39,7 @@ module.exports = async function load(sourceDir) { blogDatas, sourceDir, outDir, - themePath, + uiPath, publicPath }; }; diff --git a/lib/theme/hello.js b/lib/ui/hello.js similarity index 100% rename from lib/theme/hello.js rename to lib/ui/hello.js diff --git a/lib/theme/layout.js b/lib/ui/layout.js similarity index 100% rename from lib/theme/layout.js rename to lib/ui/layout.js diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 069a6de38f..4bd05e16e3 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -2,7 +2,7 @@ const Config = require('webpack-chain'); const path = require('path'); module.exports = function createBaseConfig(props) { - const {outDir, themePath, sourceDir, publicPath} = props; + const {outDir, uiPath, sourceDir, publicPath} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -17,7 +17,7 @@ module.exports = function createBaseConfig(props) { config.resolve .set('symlinks', true) - .alias.set('@theme', themePath) + .alias.set('@ui', uiPath) .set('@source', sourceDir) .set('@generated', path.resolve(__dirname, '../generated')) .set('@core', path.resolve(__dirname, '../core')) diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js index 8a2e5cd182..58613caf85 100644 --- a/lib/webpack/dev.js +++ b/lib/webpack/dev.js @@ -4,7 +4,7 @@ const createBaseConfig = require('./base'); module.exports = function createDevConfig(props) { const config = createBaseConfig(props); - config.entry('main').add(path.resolve(__dirname, '../core/index.js')); + config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); return config; }; From 50894d824d2666ab5edc7f0e9e38a40019ce50b1 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 18:02:35 +0800 Subject: [PATCH 026/135] feat: use webpackbar --- lib/commands/dev.js | 11 +++++-- package.json | 4 +-- yarn.lock | 80 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/lib/commands/dev.js b/lib/commands/dev.js index dd3b0ec62e..46559011e5 100644 --- a/lib/commands/dev.js +++ b/lib/commands/dev.js @@ -10,8 +10,8 @@ const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); -const serveWaitpage = require('webpack-serve-waitpage'); const webpackNiceLog = require('webpack-nicelog'); +const webpackBar = require('webpackbar'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../loader'); const createDevConfig = require('../webpack/dev'); @@ -46,8 +46,14 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // resolve webpack config let config = createDevConfig(props); + config.plugin('WebpackBar').use(webpackBar, [ + { + compiledIn: false + } + ]); config.plugin('WebpackNiceLog').use(webpackNiceLog, [ { + compileMessage: 'none', onDone: () => { console.log( `\n${chalk.blue('Development server available at ')}${chalk.cyan( @@ -77,7 +83,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { { content: [nonExistentDir], compiler, - open: true, + open: false, devMiddleware: { logLevel: 'silent' }, @@ -92,7 +98,6 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { if (fs.existsSync(staticDir)) { app.use(mount(publicPath, serveStatic(staticDir))); } - app.use(serveWaitpage(options, {theme: 'dark'})); // https://github.com/elisherer/webpack-serve-waitpage#middleware-options app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 app.use( convert( diff --git a/package.json b/package.json index 609f7d157e..ea7ce42a0d 100644 --- a/package.json +++ b/package.json @@ -62,9 +62,9 @@ "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", - "webpack-nicelog": "^1.0.1", + "webpack-nicelog": "^1.1.0", "webpack-serve": "^2.0.2", - "webpack-serve-waitpage": "^1.0.1" + "webpackbar": "^2.6.1" }, "engines": { "node": ">=8" diff --git a/yarn.lock b/yarn.lock index 52e0357881..dc6fad9ac7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -275,7 +275,7 @@ ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" -ajv-keywords@^3.1.0: +ajv-keywords@^3.0.0, ajv-keywords@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" @@ -288,7 +288,7 @@ ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0: +ajv@^6.0.1, ajv@^6.1.0: version "6.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" dependencies: @@ -1482,7 +1482,7 @@ cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" -cli-cursor@^2.1.0: +cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: @@ -1602,6 +1602,15 @@ connect-history-api-fallback@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" +consola@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/consola/-/consola-1.4.1.tgz#4b1c6259c8db23f51e7cfb68cd383ec5ee298f0e" + dependencies: + chalk "^2.3.2" + figures "^2.0.0" + lodash "^4.17.5" + std-env "^1.1.0" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -2055,10 +2064,6 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ejs@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" - electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" @@ -3224,7 +3229,7 @@ is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" -is-ci@^1.0.10: +is-ci@^1.0.10, is-ci@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" dependencies: @@ -4177,7 +4182,7 @@ lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -4187,6 +4192,14 @@ log-symbols@^2.1.0, log-symbols@^2.2.0: dependencies: chalk "^2.0.1" +log-update@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + dependencies: + ansi-escapes "^3.0.0" + cli-cursor "^2.0.0" + wrap-ansi "^3.0.1" + loglevelnext@^1.0.1, loglevelnext@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" @@ -5140,6 +5153,10 @@ pretty-format@^23.2.0: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-time@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -5992,6 +6009,12 @@ static-extend@^0.1.1: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" +std-env@^1.1.0, std-env@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-1.3.1.tgz#4e1758412439e9ece1d437b1b098551911aa44ee" + dependencies: + is-ci "^1.1.0" + stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -6125,6 +6148,17 @@ table@4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" +table@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" + dependencies: + ajv "^6.0.1" + ajv-keywords "^3.0.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" @@ -6621,12 +6655,6 @@ webpack-nicelog@^1.0.1: ora "^3.0.0" react-dev-utils "^5.0.1" -webpack-serve-waitpage@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/webpack-serve-waitpage/-/webpack-serve-waitpage-1.0.1.tgz#8aee5bf8aafcf997c72a74fc48ae1c495001fde9" - dependencies: - ejs "^2.6.1" - webpack-serve@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/webpack-serve/-/webpack-serve-2.0.2.tgz#6263b7c2888e169f84105da2119079098512b404" @@ -6700,6 +6728,21 @@ webpack@^4.16.3: watchpack "^1.5.0" webpack-sources "^1.0.1" +webpackbar@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-2.6.1.tgz#d1aff0665c43635ff35672be2f2463d1176bdb6f" + dependencies: + chalk "^2.3.2" + consola "^1.2.0" + figures "^2.0.0" + loader-utils "^1.1.0" + lodash "^4.17.5" + log-update "^2.3.0" + pretty-time "^1.0.0" + schema-utils "^0.4.5" + std-env "^1.3.0" + table "^4.0.3" + websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" @@ -6784,6 +6827,13 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" From 2ba359f4ed8069ac10c08cc58d0d5705e7df9b5f Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 18:09:35 +0800 Subject: [PATCH 027/135] chore: delay starting webpack-serve by one second --- lib/commands/dev.js | 60 +++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/commands/dev.js b/lib/commands/dev.js index 46559011e5..494a0303b2 100644 --- a/lib/commands/dev.js +++ b/lib/commands/dev.js @@ -78,35 +78,37 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // webpack-serve const nonExistentDir = path.resolve(__dirname, 'non-existent'); - await serve( - {}, - { - content: [nonExistentDir], - compiler, - open: false, - devMiddleware: { - logLevel: 'silent' - }, - hotClient: { - port: port + 1, - logLevel: 'error' - }, - logLevel: 'error', - port, - add: (app, middleware, options) => { - const staticDir = path.resolve(sourceDir, 'public'); - if (fs.existsSync(staticDir)) { - app.use(mount(publicPath, serveStatic(staticDir))); + setTimeout(async () => { + await serve( + {}, + { + content: [nonExistentDir], + compiler, + open: false, + devMiddleware: { + logLevel: 'silent' + }, + hotClient: { + port: port + 1, + logLevel: 'error' + }, + logLevel: 'error', + port, + add: (app, middleware, options) => { + const staticDir = path.resolve(sourceDir, 'public'); + if (fs.existsSync(staticDir)) { + app.use(mount(publicPath, serveStatic(staticDir))); + } + app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 + app.use( + convert( + history({ + rewrites: [{from: /\.html$/, to: '/'}] + }) + ) + ); } - app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 - app.use( - convert( - history({ - rewrites: [{from: /\.html$/, to: '/'}] - }) - ) - ); } - } - ); + ); + }, 1000); }; From 75ed92e7975850d5fbe652cda4ee5abdd76a9582 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 1 Aug 2018 18:30:24 +0800 Subject: [PATCH 028/135] chore: add sakura.png to test static file --- examples/public/sakura.png | Bin 0 -> 79340 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/public/sakura.png diff --git a/examples/public/sakura.png b/examples/public/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 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 DKbw08 literal 0 HcmV?d00001 From 44eb7655cab6344abb026c70b879a04c4745f1f7 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 4 Aug 2018 18:13:45 +0800 Subject: [PATCH 029/135] chore: update webpack-nicelog to v2 --- lib/commands/dev.js | 8 +------- package.json | 5 ++--- yarn.lock | 43 ++++++------------------------------------- 3 files changed, 9 insertions(+), 47 deletions(-) diff --git a/lib/commands/dev.js b/lib/commands/dev.js index 494a0303b2..2a1a47a856 100644 --- a/lib/commands/dev.js +++ b/lib/commands/dev.js @@ -11,7 +11,6 @@ const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); const webpackNiceLog = require('webpack-nicelog'); -const webpackBar = require('webpackbar'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../loader'); const createDevConfig = require('../webpack/dev'); @@ -46,14 +45,9 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { // resolve webpack config let config = createDevConfig(props); - config.plugin('WebpackBar').use(webpackBar, [ - { - compiledIn: false - } - ]); config.plugin('WebpackNiceLog').use(webpackNiceLog, [ { - compileMessage: 'none', + name: 'Blogi', onDone: () => { console.log( `\n${chalk.blue('Development server available at ')}${chalk.cyan( diff --git a/package.json b/package.json index ea7ce42a0d..15930bdf3f 100644 --- a/package.json +++ b/package.json @@ -62,9 +62,8 @@ "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", - "webpack-nicelog": "^1.1.0", - "webpack-serve": "^2.0.2", - "webpackbar": "^2.6.1" + "webpack-nicelog": "^2.0.0", + "webpack-serve": "^2.0.2" }, "engines": { "node": ">=8" diff --git a/yarn.lock b/yarn.lock index dc6fad9ac7..88553e302e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1407,7 +1407,7 @@ chalk@1.1.3, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: @@ -1488,10 +1488,6 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-spinners@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -1519,10 +1515,6 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1861,12 +1853,6 @@ default-require-extensions@^2.0.0: dependencies: strip-bom "^3.0.0" -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - dependencies: - clone "^1.0.2" - define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -4186,7 +4172,7 @@ lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" -log-symbols@^2.1.0, log-symbols@^2.2.0: +log-symbols@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" dependencies: @@ -4841,17 +4827,6 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -ora@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.0.0.tgz#8179e3525b9aafd99242d63cc206fd64732741d0" - dependencies: - chalk "^2.3.1" - cli-cursor "^2.1.0" - cli-spinners "^1.1.0" - log-symbols "^2.2.0" - strip-ansi "^4.0.0" - wcwidth "^1.0.1" - original@>=0.0.5: version "1.0.1" resolved "https://registry.yarnpkg.com/original/-/original-1.0.1.tgz#b0a53ff42ba997a8c9cd1fb5daaeb42b9d693190" @@ -6596,12 +6571,6 @@ watchpack@^1.5.0: graceful-fs "^4.1.2" neo-async "^2.5.0" -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - dependencies: - defaults "^1.0.3" - webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -6647,13 +6616,13 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: loglevelnext "^1.0.1" uuid "^3.1.0" -webpack-nicelog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-1.0.1.tgz#64ae1a7c17c793c1edede0ea0d9540999a04dd62" +webpack-nicelog@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.0.0.tgz#7e4d68c54e7bd82adf19fde1eb3d43e767eea887" dependencies: chalk "^2.4.1" - ora "^3.0.0" react-dev-utils "^5.0.1" + webpackbar "^2.6.1" webpack-serve@^2.0.2: version "2.0.2" From 45cf88e0594c64f28b853619f2aac5e3518d5b3f Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 14:54:20 +0800 Subject: [PATCH 030/135] refactor: use docusaurus structure --- .gitignore | 1 + README.md | 3 +- bin/blogi.js | 58 ---------------- bin/munseo.js | 65 ++++++++++++++++++ docs/foo/bar.md | 6 ++ docs/foo/baz.md | 6 ++ docs/hello.md | 6 ++ docs/intro.md | 6 ++ examples/config.js | 4 -- examples/foo/bar.md | 6 -- examples/foo/baz.md | 5 -- examples/hello-world.md | 12 ---- lib/commands/build.js | 5 +- lib/commands/init.js | 7 ++ lib/commands/{dev.js => start.js} | 14 ++-- lib/index.js | 8 +-- lib/loader/blog.js | 8 +-- lib/loader/config.js | 4 +- lib/loader/index.js | 12 ++-- lib/webpack/base.js | 4 +- package.json | 19 ++--- website/package.json | 9 +++ website/siteConfig.js | 7 ++ .../public => website/static}/sakura.png | Bin 24 files changed, 152 insertions(+), 123 deletions(-) delete mode 100644 bin/blogi.js create mode 100644 bin/munseo.js create mode 100644 docs/foo/bar.md create mode 100644 docs/foo/baz.md create mode 100644 docs/hello.md create mode 100644 docs/intro.md delete mode 100644 examples/config.js delete mode 100644 examples/foo/bar.md delete mode 100644 examples/foo/baz.md delete mode 100644 examples/hello-world.md create mode 100644 lib/commands/init.js rename lib/commands/{dev.js => start.js} (87%) create mode 100644 website/package.json create mode 100644 website/siteConfig.js rename {examples/public => website/static}/sakura.png (100%) diff --git a/.gitignore b/.gitignore index c9da630db9..21ee9db9eb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules dist yarn-error.log generated +website/node_modules diff --git a/README.md b/README.md index 2b497c97b0..e68887c70b 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# blogi +# Munseo +📝⚡️ Transform your document (문서) to a website \ No newline at end of file diff --git a/bin/blogi.js b/bin/blogi.js deleted file mode 100644 index e58c5861ef..0000000000 --- a/bin/blogi.js +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env node - -const chalk = require('chalk'); -const semver = require('semver'); -const path = require('path'); -const program = require('commander'); -const {dev, build} = require('../lib'); -const requiredVersion = require('../package.json').engines.node; - -if (!semver.satisfies(process.version, requiredVersion)) { - console.log( - chalk.red(`\nMinimum node version not met :)`) + - chalk.yellow( - `\nYou are using Node ${ - process.version - }, but blogi requires Node ${requiredVersion}.\n` - ) - ); - process.exit(1); -} - -function wrapCommand(fn) { - return (...args) => - fn(...args).catch(err => { - console.error(chalk.red(err.stack)); - process.exitCode = 1; - }); -} - -program - .version(require('../package.json').version) - .usage(' [options]'); - -program - .command('dev [targetDir]') - .description('start development server') - .option('-p, --port ', 'use specified port (default: 8080)') - .action((dir = '.', {port}) => { - wrapCommand(dev)(path.resolve(dir), {port}); - }); - -program - .command('build [targetDir]') - .description('build dir as static site') - .option( - '-d, --dest ', - 'specify build output dir (default: .blogi/dist)' - ) - .action((dir = '.', {dest}) => { - const outDir = dest ? path.resolve(dest) : null; - wrapCommand(build)(path.resolve(dir), {outDir}); - }); - -program.parse(process.argv); - -if (!process.argv.slice(2).length) { - program.outputHelp(); -} diff --git a/bin/munseo.js b/bin/munseo.js new file mode 100644 index 0000000000..927b884a85 --- /dev/null +++ b/bin/munseo.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +const chalk = require('chalk'); +const semver = require('semver'); +const path = require('path'); +const program = require('commander'); +const {build, init, start} = require('../lib'); +const requiredVersion = require('../package.json').engines.node; + +if (!semver.satisfies(process.version, requiredVersion)) { + console.log( + chalk.red(`\nMinimum node version not met :)`) + + chalk.yellow( + `\nYou are using Node ${ + process.version + }, Requirement: Node ${requiredVersion}.\n` + ) + ); + process.exit(1); +} + +function wrapCommand(fn) { + return (...args) => + fn(...args).catch(err => { + console.error(chalk.red(err.stack)); + process.exitCode = 1; + }); +} + +program + .version(require('../package.json').version) + .usage(' [options]'); + +program + .command('build [siteDir]') + .description('Build website') + .option( + '-sic, --skip-image-compression ', + 'Skip compression of image assets (default: false)' + ) + .action((siteDir = '.', {skipImageCompression}) => { + wrapCommand(build)(path.resolve(siteDir), {skipImageCompression}); + }); + + program + .command('init [projectDir]') + .description('Initialize website') + .action((projectDir = '.') => { + wrapCommand(init)(path.resolve(projectDir)); + }); + +program + .command('start [siteDir]') + .description('Start development server') + .option('-p, --port ', 'use specified port (default: 3000)') + .option('-nw, --no-watch ', 'disable live reload (default: false)') + .action((siteDir = '.', {port, noWatch}) => { + wrapCommand(start)(path.resolve(siteDir), {port, noWatch}); + }); + +program.parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp() +} \ No newline at end of file diff --git a/docs/foo/bar.md b/docs/foo/bar.md new file mode 100644 index 0000000000..4e98647e03 --- /dev/null +++ b/docs/foo/bar.md @@ -0,0 +1,6 @@ +--- +id: bar +title: Bar +--- + +Lorem ipsumsdsdsad diff --git a/docs/foo/baz.md b/docs/foo/baz.md new file mode 100644 index 0000000000..2be434ffdc --- /dev/null +++ b/docs/foo/baz.md @@ -0,0 +1,6 @@ +--- +id: baz +title: baz +--- + +Life is so good diff --git a/docs/hello.md b/docs/hello.md new file mode 100644 index 0000000000..71fcb798ad --- /dev/null +++ b/docs/hello.md @@ -0,0 +1,6 @@ +--- +id: hello +title: Hello, World ! +--- + +Hi, Endilie here :) \ No newline at end of file diff --git a/docs/intro.md b/docs/intro.md new file mode 100644 index 0000000000..b420713204 --- /dev/null +++ b/docs/intro.md @@ -0,0 +1,6 @@ +--- +id: intro +title: Introducing Munseo +--- + +Introducing Munseo :) \ No newline at end of file diff --git a/examples/config.js b/examples/config.js deleted file mode 100644 index 14da102249..0000000000 --- a/examples/config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - title: 'Hello World', - description: 'Hello World' -}; diff --git a/examples/foo/bar.md b/examples/foo/bar.md deleted file mode 100644 index 4b28a826e3..0000000000 --- a/examples/foo/bar.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Lorem ipsum -date: 2018-06-20 ---- - -Lorem ipsumsdsdsad diff --git a/examples/foo/baz.md b/examples/foo/baz.md deleted file mode 100644 index c4e0cbf40d..0000000000 --- a/examples/foo/baz.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Baz -date: 2018-05-20 ---- -Life is so good diff --git a/examples/hello-world.md b/examples/hello-world.md deleted file mode 100644 index 451588e4c7..0000000000 --- a/examples/hello-world.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Hello, World ! -author: Endilie Yacop Sucipto -authorURL: http://twitter.com/endiliey -authorFBID: 100000251103620 ---- - -Hi, Endilie here. - - - -Random tsasshoughts, experiences, write-up of Endilie Yacop Sucipto will be shared here. diff --git a/lib/commands/build.js b/lib/commands/build.js index 34dd734731..0005a7c1ed 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -1,5 +1,6 @@ -module.exports = async function build(sourceDir, cliOptions = {}) { +module.exports = async function build(siteDir, cliOptions = {}) { process.env.NODE_ENV = 'production'; + console.log('Build command invoked ...'); + console.log(siteDir); console.log(cliOptions); - console.log('Build'); }; diff --git a/lib/commands/init.js b/lib/commands/init.js new file mode 100644 index 0000000000..cdc13aca82 --- /dev/null +++ b/lib/commands/init.js @@ -0,0 +1,7 @@ +module.exports = async function init(projectDir, cliOptions = {}) { + console.log('Init command invoked ...'); + console.log(projectDir); + console.log(cliOptions); + + // TODO +}; diff --git a/lib/commands/dev.js b/lib/commands/start.js similarity index 87% rename from lib/commands/dev.js rename to lib/commands/start.js index 2a1a47a856..ed47e49d4c 100644 --- a/lib/commands/dev.js +++ b/lib/commands/start.js @@ -16,22 +16,22 @@ const load = require('../loader'); const createDevConfig = require('../webpack/dev'); async function getPort(port) { - portfinder.basePort = parseInt(port, 10) || 8080; + portfinder.basePort = parseInt(port, 10) || 3000; return await portfinder.getPortPromise(); } -module.exports = async function dev(sourceDir, cliOptions = {}) { +module.exports = async function start(siteDir, cliOptions = {}) { // load site props from preprocessed files in source directory - const props = await load(sourceDir); + const props = await load(siteDir); // Reload for any add/change/remove of file const reload = () => { - load(sourceDir).catch(err => { + load(siteDir).catch(err => { console.error(chalk.red(err.stack)); }); }; const fsWatcher = chokidar.watch(['**/*.md', 'config.js'], { - cwd: sourceDir, + cwd: siteDir, ignoreInitial: true }); fsWatcher.on('add', reload); @@ -47,7 +47,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { let config = createDevConfig(props); config.plugin('WebpackNiceLog').use(webpackNiceLog, [ { - name: 'Blogi', + name: 'Munseo', onDone: () => { console.log( `\n${chalk.blue('Development server available at ')}${chalk.cyan( @@ -89,7 +89,7 @@ module.exports = async function dev(sourceDir, cliOptions = {}) { logLevel: 'error', port, add: (app, middleware, options) => { - const staticDir = path.resolve(sourceDir, 'public'); + const staticDir = path.resolve(siteDir, 'public'); if (fs.existsSync(staticDir)) { app.use(mount(publicPath, serveStatic(staticDir))); } diff --git a/lib/index.js b/lib/index.js index 025145a775..99577452f2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,7 +1,5 @@ -const dev = require('./commands/dev'); -const build = require('./commands/build'); - module.exports = { - dev, - build + build: require('./commands/build'), + init: require('./commands/init'), + start: require('./commands/start') }; diff --git a/lib/loader/blog.js b/lib/loader/blog.js index 58f8a0d992..13dbda3faf 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -22,14 +22,14 @@ function parse(fileString) { return {metadata, content}; } -async function loadBlog(sourceDir) { - const blogFiles = await globby(['**/*.md', '!.blogi', '!node_modules'], { - cwd: sourceDir +async function loadBlog(siteDir) { + const blogFiles = await globby(['**/*.md', '!.munseo', '!node_modules'], { + cwd: siteDir }); const blogDatas = await Promise.all( blogFiles.map(async file => { - const filepath = path.resolve(sourceDir, file); + const filepath = path.resolve(siteDir, file); const fileString = await fs.readFile(filepath, 'utf-8'); const {metadata, content} = parse(fileString); diff --git a/lib/loader/config.js b/lib/loader/config.js index fcdcbef3d1..6656aab290 100644 --- a/lib/loader/config.js +++ b/lib/loader/config.js @@ -1,8 +1,8 @@ const fs = require('fs-extra'); const path = require('path'); -module.exports = function loadConfig(sourceDir, deleteCache = true) { - const configPath = path.resolve(sourceDir, 'config.js'); +module.exports = function loadConfig(siteDir, deleteCache = true) { + const configPath = path.resolve(siteDir, 'config.js'); if (deleteCache) { delete require.cache[configPath]; } diff --git a/lib/loader/index.js b/lib/loader/index.js index f6e69ab56a..b9cc66eda0 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -4,12 +4,12 @@ const loadConfig = require('./config'); const loadBlog = require('./blog'); const {generate} = require('../helpers'); -module.exports = async function load(sourceDir) { +module.exports = async function load(siteDir) { // load siteConfig - const siteConfig = loadConfig(sourceDir); + const siteConfig = loadConfig(siteDir); // extract data from all blog files - const blogDatas = await loadBlog(sourceDir); + const blogDatas = await loadBlog(siteDir); await generate( 'blogDatas.js', @@ -23,12 +23,12 @@ module.exports = async function load(sourceDir) { // resolve outDir const outDir = siteConfig.dest ? path.resolve(siteConfig.dest) - : path.resolve(sourceDir, '.blogi/dist'); + : path.resolve(siteDir, '.munseo/dist'); // resolve the path of our app user interface layout const uiPath = !siteConfig.uiPath || - !fs.existsSync(path.resolve(sourceDir, siteConfig.uiPath)) + !fs.existsSync(path.resolve(siteDir, siteConfig.uiPath)) ? path.resolve(__dirname, '../ui') : siteConfig.uiPath; @@ -37,7 +37,7 @@ module.exports = async function load(sourceDir) { return { siteConfig, blogDatas, - sourceDir, + siteDir, outDir, uiPath, publicPath diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 4bd05e16e3..29bffe0567 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -2,7 +2,7 @@ const Config = require('webpack-chain'); const path = require('path'); module.exports = function createBaseConfig(props) { - const {outDir, uiPath, sourceDir, publicPath} = props; + const {outDir, uiPath, siteDir, publicPath} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -18,7 +18,7 @@ module.exports = function createBaseConfig(props) { config.resolve .set('symlinks', true) .alias.set('@ui', uiPath) - .set('@source', sourceDir) + .set('@source', siteDir) .set('@generated', path.resolve(__dirname, '../generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); diff --git a/package.json b/package.json index 15930bdf3f..4218cdff92 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,22 @@ { - "name": "blogi", - "version": "1.0.0", - "description": "Blog instantly", + "name": "munseo", + "version": "0.0.1", + "description": "📝⚡️ Transform your document (문서) to a website", "main": "lib/index.js", "bin": { - "blogi": "bin/blogi.js" + "munseo": "bin/munseo.js" }, "scripts": { - "dev": "node bin/blogi dev examples", - "build": "node bin/blogi build examples", + "munseo": "node bin/munseo", + "start": "yarn munseo start website", + "build": "yarn munseo build website", "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "test": "jest" }, "repository": { "type": "git", - "url": "git+https://github.com/endiliey/blogi.git" + "url": "git+https://github.com/endiliey/munseo.git" }, "keywords": [ "blog", @@ -25,9 +26,9 @@ "author": "endiliey", "license": "MIT", "bugs": { - "url": "https://github.com/endiliey/blogi/issues" + "url": "https://github.com/endiliey/munseo/issues" }, - "homepage": "https://github.com/endiliey/blogi#readme", + "homepage": "https://github.com/endiliey/munseo#readme", "devDependencies": { "eslint": "^4.19.1", "eslint-config-airbnb": "17.0.0", diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000000..050e454bfb --- /dev/null +++ b/website/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "start": "node ../bin/munseo start", + "build": "node ../bin/munseo build" + }, + "dependencies": { + "munseo": "../../munseo/" + } +} \ No newline at end of file diff --git a/website/siteConfig.js b/website/siteConfig.js new file mode 100644 index 0000000000..7155f839a6 --- /dev/null +++ b/website/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Munseo', + tagline: '📝⚡️ Transform your document (문서) to a website', + organizationName: 'endiliey', + projectName: 'munseo', + baseUrl: '/' +}; diff --git a/examples/public/sakura.png b/website/static/sakura.png similarity index 100% rename from examples/public/sakura.png rename to website/static/sakura.png From b37d9922546156142482b929979d7bb25c387b61 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 16:25:32 +0800 Subject: [PATCH 031/135] chore: add dummy blog file --- website/blog/2018-08-05-sakura.md | 11 +++++++++++ website/static/{ => img}/sakura.png | Bin 2 files changed, 11 insertions(+) create mode 100644 website/blog/2018-08-05-sakura.md rename website/static/{ => img}/sakura.png (100%) diff --git a/website/blog/2018-08-05-sakura.md b/website/blog/2018-08-05-sakura.md new file mode 100644 index 0000000000..68668e018b --- /dev/null +++ b/website/blog/2018-08-05-sakura.md @@ -0,0 +1,11 @@ +--- +title: Sakura +author: Endilie +authorURL: https://github.com/endiliey +authorFBID: 100000251103620 +authorTwitter: endiliey +--- + +![Sakura](/img/sakura.png) + +Sakura Miyawaki (宮脇 咲良 Miyawaki Sakura, born 19 March 1998) is a Japanese singer and a member of the Japanese idol girl groups HKT48 and AKB48. She is vice-captain of HKT48's Team KIV and former concurrent member of AKB48's Team A. \ No newline at end of file diff --git a/website/static/sakura.png b/website/static/img/sakura.png similarity index 100% rename from website/static/sakura.png rename to website/static/img/sakura.png From 05426d4e2c6ad107b94a75353875c72449daff60 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 18:06:13 +0800 Subject: [PATCH 032/135] feat: add react component for markdown->html --- lib/core/markdown/anchors.js | 21 +++++++ lib/core/markdown/index.js | 111 +++++++++++++++++++++++++++++++++++ lib/core/markdown/toSlug.js | 66 +++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 lib/core/markdown/anchors.js create mode 100644 lib/core/markdown/index.js create mode 100644 lib/core/markdown/toSlug.js diff --git a/lib/core/markdown/anchors.js b/lib/core/markdown/anchors.js new file mode 100644 index 0000000000..2598635e2d --- /dev/null +++ b/lib/core/markdown/anchors.js @@ -0,0 +1,21 @@ +const toSlug = require('./toSlug.js'); + +function anchors(md) { + const originalRender = md.renderer.rules.heading_open; + + md.renderer.rules.heading_open = function(tokens, idx, options, env) { + const textToken = tokens[idx + 1]; + + if (textToken.content) { + const anchor = toSlug(textToken.content, env); + + return ``; + } + + return originalRender(tokens, idx, options, env); + }; +} + +module.exports = anchors; diff --git a/lib/core/markdown/index.js b/lib/core/markdown/index.js new file mode 100644 index 0000000000..038765c7e3 --- /dev/null +++ b/lib/core/markdown/index.js @@ -0,0 +1,111 @@ +import React from 'react'; +import Markdown from 'remarkable'; +import hljs from 'highlight.js'; +import prismjs from 'prismjs'; + +import anchors from './anchors.js'; + +class MarkdownBlock extends React.Component { + renderMarkdown(source) { + const alias = { + js: 'jsx' + }; + const md = new Markdown({ + langPrefix: 'hljs css language-', + highlight(str, lang) { + lang = + lang || (siteConfig.highlight && siteConfig.highlight.defaultLang); + if (lang === 'text') { + return str; + } + if (lang) { + try { + if ( + siteConfig.usePrism === true || + (siteConfig.usePrism && + siteConfig.usePrism.length > 0 && + siteConfig.usePrism.indexOf(lang) !== -1) + ) { + try { + const language = alias[lang] || lang; + // Currently people using prismjs on Node have to individually require() + // every single language (https://github.com/PrismJS/prism/issues/593) + require(`prismjs/components/prism-${language}.min`); + return prismjs.highlight(str, prismjs.languages[language]); + } catch (err) { + console.error(err); + } + } + if (hljs.getLanguage(lang)) { + return hljs.highlight(lang, str).value; + } + } catch (err) { + console.error(err); + } + } + + try { + return hljs.highlightAuto(str).value; + } catch (err) { + console.error(err); + } + + return ''; + }, + html: true, + linkify: true + }); + + // Register anchors plugin + md.use(anchors); + + // Allow client sites to register their own plugins + if (siteConfig.markdownPlugins) { + siteConfig.markdownPlugins.forEach(plugin => { + md.use(plugin); + }); + } + + const html = md.render(source); + + // Ensure fenced code blocks use Highlight.js hljs class + // https://github.com/jonschlinkert/remarkable/issues/224 + return html.replace(/

/g, '
');
+  }
+
+  content() {
+    if (this.props.source) {
+      return (
+        
+      );
+    } else {
+      return React.Children.map(this.props.children, child => {
+        if (typeof child === 'string') {
+          return (
+            
+          );
+        } else {
+          return child;
+        }
+      });
+    }
+  }
+
+  render() {
+    const Container = this.props.container;
+    return {this.content()};
+  }
+}
+
+MarkdownBlock.defaultProps = {
+  container: 'div',
+  siteConfig: {}
+};
+
+export default MarkdownBlock;
diff --git a/lib/core/markdown/toSlug.js b/lib/core/markdown/toSlug.js
new file mode 100644
index 0000000000..aa7ad39df0
--- /dev/null
+++ b/lib/core/markdown/toSlug.js
@@ -0,0 +1,66 @@
+const letters =
+  '\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC';
+const numbers =
+  '\u0030-\u0039\u00B2\u00B3\u00B9\u00BC-\u00BE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19';
+const exceptAlphanum = new RegExp(`[^${[letters, numbers].join('')}]`, 'g');
+
+/**
+ * Converts a string to a slug, that can be used in heading anchors
+ *
+ * @param  {string} string
+ * @param  {Object} [context={}] - an optional context to track used slugs and
+ *                                 ensure that new slug will be unique
+ *
+ * @return {string}
+ */
+module.exports = (string, context = {}) => {
+  //  var accents = "àáäâèéëêìíïîòóöôùúüûñç";
+  const accents =
+    '\u00e0\u00e1\u00e4\u00e2\u00e8' +
+    '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' +
+    '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' +
+    '\u00fa\u00fc\u00fb\u00f1\u00e7';
+
+  const without = 'aaaaeeeeiiiioooouuuunc';
+
+  let slug = string
+    .toString()
+    // Handle uppercase characters
+    .toLowerCase()
+    // Handle accentuated characters
+    .replace(new RegExp(`[${accents}]`, 'g'), c =>
+      without.charAt(accents.indexOf(c))
+    )
+    // Replace `.`, `(` and `?` with blank string like Github does
+    .replace(/\.|\(|\?/g, '')
+    // Dash special characters
+    .replace(exceptAlphanum, '-')
+    // Compress multiple dash
+    .replace(/-+/g, '-')
+    // Trim dashes
+    .replace(/^-|-$/g, '');
+
+  // Add trailing `-` if string contains ` ...` in the end like Github does
+  if (/\s[.]{1,}/.test(string)) {
+    slug += '-';
+  }
+
+  if (!context.slugStats) {
+    context.slugStats = {};
+  }
+
+  if (typeof context.slugStats[slug] === 'number') {
+    // search for an index, that will not clash with an existing headings
+    while (
+      typeof context.slugStats[`${slug}-${++context.slugStats[slug]}`] ===
+      'number'
+    );
+    slug += `-${context.slugStats[slug]}`;
+  }
+
+  // we are tracking both original anchors and suffixed to avoid future name
+  // clashing with headings with numbers e.g. `#Foo 1` may clash with the second `#Foo`
+  context.slugStats[slug] = 0;
+
+  return slug;
+};

From 187a46d9b617914fef271f1b8c194082ca8cbb94 Mon Sep 17 00:00:00 2001
From: endiliey 
Date: Sun, 5 Aug 2018 18:58:50 +0800
Subject: [PATCH 033/135] chore: prettier

---
 bin/munseo.js         |  6 +++---
 lib/commands/start.js | 40 +++++++++++++++++++++-------------------
 2 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/bin/munseo.js b/bin/munseo.js
index 927b884a85..75ad89e773 100644
--- a/bin/munseo.js
+++ b/bin/munseo.js
@@ -42,7 +42,7 @@ program
     wrapCommand(build)(path.resolve(siteDir), {skipImageCompression});
   });
 
-  program
+program
   .command('init [projectDir]')
   .description('Initialize website')
   .action((projectDir = '.') => {
@@ -61,5 +61,5 @@ program
 program.parse(process.argv);
 
 if (!process.argv.slice(2).length) {
-  program.outputHelp()
-}
\ No newline at end of file
+  program.outputHelp();
+}
diff --git a/lib/commands/start.js b/lib/commands/start.js
index ed47e49d4c..284bd45543 100644
--- a/lib/commands/start.js
+++ b/lib/commands/start.js
@@ -21,27 +21,29 @@ async function getPort(port) {
 }
 
 module.exports = async function start(siteDir, cliOptions = {}) {
-  // load site props from preprocessed files in source directory
+  // Preprocess whole files as a prop
   const props = await load(siteDir);
 
-  // Reload for any add/change/remove of file
-  const reload = () => {
-    load(siteDir).catch(err => {
-      console.error(chalk.red(err.stack));
+  // (if enabled) live reload for any changes in file
+  if (!cliOptions.noWatch) {
+    const reload = () => {
+      load(siteDir).catch(err => {
+        console.error(chalk.red(err.stack));
+      });
+    };
+    const fsWatcher = chokidar.watch(['../docs/**/*.md', 'siteConfig.js'], {
+      cwd: siteDir,
+      ignoreInitial: true
     });
-  };
-  const fsWatcher = chokidar.watch(['**/*.md', 'config.js'], {
-    cwd: siteDir,
-    ignoreInitial: true
-  });
-  fsWatcher.on('add', reload);
-  fsWatcher.on('change', reload);
-  fsWatcher.on('unlink', reload);
-  fsWatcher.on('addDir', reload);
-  fsWatcher.on('unlinkDir', reload);
+    fsWatcher.on('add', reload);
+    fsWatcher.on('change', reload);
+    fsWatcher.on('unlink', reload);
+    fsWatcher.on('addDir', reload);
+    fsWatcher.on('unlinkDir', reload);
+  }
 
   const port = await getPort(cliOptions.port);
-  const {publicPath} = props;
+  const {baseUrl} = props;
 
   // resolve webpack config
   let config = createDevConfig(props);
@@ -51,7 +53,7 @@ module.exports = async function start(siteDir, cliOptions = {}) {
       onDone: () => {
         console.log(
           `\n${chalk.blue('Development server available at ')}${chalk.cyan(
-            `http://localhost:${port}${publicPath}`
+            `http://localhost:${port}${baseUrl}`
           )}`
         );
       }
@@ -89,9 +91,9 @@ module.exports = async function start(siteDir, cliOptions = {}) {
         logLevel: 'error',
         port,
         add: (app, middleware, options) => {
-          const staticDir = path.resolve(siteDir, 'public');
+          const staticDir = path.resolve(siteDir, 'static');
           if (fs.existsSync(staticDir)) {
-            app.use(mount(publicPath, serveStatic(staticDir)));
+            app.use(mount(baseUrl, serveStatic(staticDir)));
           }
           app.use(range); // enable range request https://tools.ietf.org/html/rfc7233
           app.use(

From 221023fd51176cf321afd137c3e4e56da08afae7 Mon Sep 17 00:00:00 2001
From: endiliey 
Date: Sun, 5 Aug 2018 18:59:23 +0800
Subject: [PATCH 034/135] feat: prototype blog & docs generation on dev

---
 lib/core/blog/index.js     | 11 +++++++
 lib/core/blogPost.js       | 13 --------
 lib/core/devEntry.js       | 29 +++++++++++-------
 lib/core/docs/index.js     | 11 +++++++
 lib/core/markdown/index.js |  4 +++
 lib/loader/blog.js         |  3 +-
 lib/loader/config.js       |  2 +-
 lib/loader/docs.js         | 47 +++++++++++++++++++++++++++++
 lib/loader/index.js        | 29 +++++++++++++-----
 lib/webpack/base.js        |  4 +--
 package.json               |  3 ++
 yarn.lock                  | 62 ++++++++++++++++++++++++++++++++++++++
 12 files changed, 181 insertions(+), 37 deletions(-)
 create mode 100644 lib/core/blog/index.js
 delete mode 100644 lib/core/blogPost.js
 create mode 100644 lib/core/docs/index.js
 create mode 100644 lib/loader/docs.js

diff --git a/lib/core/blog/index.js b/lib/core/blog/index.js
new file mode 100644
index 0000000000..f5f1bf7b69
--- /dev/null
+++ b/lib/core/blog/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import MarkdownBlock from '../markdown';
+
+class Docs extends React.Component {
+  render() {
+    const {content, siteConfig} = this.props;
+    return {content};
+  }
+}
+
+module.exports = Docs;
diff --git a/lib/core/blogPost.js b/lib/core/blogPost.js
deleted file mode 100644
index 0698cf6581..0000000000
--- a/lib/core/blogPost.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import blogDatas from '@generated/blogDatas';
-
-// inner blog component for the article itself, without sidebar/header/footer
-class BlogPost extends React.Component {
-  render() {
-    const {match} = this.props;
-    const post = blogDatas.find(blog => blog.path === match.path);
-    return 
{post && post.content}
; - } -} - -module.exports = BlogPost; diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js index 8fb024c577..ebf7322b07 100644 --- a/lib/core/devEntry.js +++ b/lib/core/devEntry.js @@ -1,8 +1,19 @@ import React from 'react'; import {render} from 'react-dom'; import {BrowserRouter, Route, Switch, Link} from 'react-router-dom'; -import blogDatas from '@generated/blogDatas'; -import BlogPost from './blogPost'; +import blogMetadata from '@generated/blogMetadata'; +import docsMetadata from '@generated/docsMetadata'; +import Blog from './blog'; +import Docs from './docs'; + +const renderBlog = props => { + const metadata = blogMetadata.find(blog => blog.path === props.match.path); + return ; +}; +const renderDocs = props => { + const metadata = docsMetadata.find(doc => doc.path === props.match.path); + return ; +}; class App extends React.Component { render() { @@ -10,17 +21,13 @@ class App extends React.Component {
- {blogDatas.map(({path}) => ( - + {blogMetadata.map(({path, content}) => ( + + ))} + {docsMetadata.map(({path}) => ( + ))} -
- {blogDatas.map(({path}) => ( -
- {path} -
- ))} -
); diff --git a/lib/core/docs/index.js b/lib/core/docs/index.js new file mode 100644 index 0000000000..1134a6e8d3 --- /dev/null +++ b/lib/core/docs/index.js @@ -0,0 +1,11 @@ +import React from 'react'; +import MarkdownBlock from '../markdown'; + +class Blog extends React.Component { + render() { + const {content, siteConfig} = this.props; + return {content}; + } +} + +module.exports = Blog; diff --git a/lib/core/markdown/index.js b/lib/core/markdown/index.js index 038765c7e3..c50ab500bf 100644 --- a/lib/core/markdown/index.js +++ b/lib/core/markdown/index.js @@ -10,6 +10,7 @@ class MarkdownBlock extends React.Component { const alias = { js: 'jsx' }; + const {siteConfig} = this.props; const md = new Markdown({ langPrefix: 'hljs css language-', highlight(str, lang) { @@ -99,6 +100,9 @@ class MarkdownBlock extends React.Component { render() { const Container = this.props.container; + if (!Container) { + return
{this.content()}
; + } return {this.content()}; } } diff --git a/lib/loader/blog.js b/lib/loader/blog.js index 13dbda3faf..da54415a74 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -36,8 +36,7 @@ async function loadBlog(siteDir) { return { path: fileToPath(file), content, - title: metadata.title, - date: metadata.date + ...metadata }; }) ); diff --git a/lib/loader/config.js b/lib/loader/config.js index 6656aab290..557edef3e2 100644 --- a/lib/loader/config.js +++ b/lib/loader/config.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); module.exports = function loadConfig(siteDir, deleteCache = true) { - const configPath = path.resolve(siteDir, 'config.js'); + const configPath = path.resolve(siteDir, 'siteConfig.js'); if (deleteCache) { delete require.cache[configPath]; } diff --git a/lib/loader/docs.js b/lib/loader/docs.js new file mode 100644 index 0000000000..a117b5deeb --- /dev/null +++ b/lib/loader/docs.js @@ -0,0 +1,47 @@ +const fs = require('fs-extra'); +const path = require('path'); +const fm = require('front-matter'); +const globby = require('globby'); + +const indexRE = /(^|.*\/)index\.md$/i; +const mdRE = /\.md$/; + +function fileToPath(file) { + if (indexRE.test(file)) { + return file.replace(indexRE, '/$1'); + } + return `/${file.replace(mdRE, '').replace(/\\/g, '/')}.html`; +} + +function parse(fileString) { + if (!fm.test(fileString)) { + return {metadata: null, content: fileString}; + } + const {attributes: metadata, body: content} = fm(fileString); + + return {metadata, content}; +} + +async function loadDocs(siteDir) { + const blogFiles = await globby(['**/*.md'], { + cwd: siteDir + }); + + const blogDatas = await Promise.all( + blogFiles.map(async file => { + const filepath = path.resolve(siteDir, file); + const fileString = await fs.readFile(filepath, 'utf-8'); + const {metadata, content} = parse(fileString); + + return { + path: fileToPath(file), + content, + ...metadata + }; + }) + ); + blogDatas.sort((a, b) => b.date - a.date); + return blogDatas; +} + +module.exports = loadDocs; diff --git a/lib/loader/index.js b/lib/loader/index.js index b9cc66eda0..cd56932b5a 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -2,19 +2,33 @@ const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); const loadBlog = require('./blog'); +const loadDocs = require('./docs'); const {generate} = require('../helpers'); module.exports = async function load(siteDir) { // load siteConfig const siteConfig = loadConfig(siteDir); - // extract data from all blog files - const blogDatas = await loadBlog(siteDir); - + // docs + const docsRelativeDir = siteConfig.customDocsPath || 'docs'; + const docsMetadata = await loadDocs( + path.resolve(siteDir, '..', docsRelativeDir) + ); await generate( - 'blogDatas.js', + 'docsMetadata.js', `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( - blogDatas, + docsMetadata, + null, + 2 + )};\n` + ); + + // blog + const blogMetadata = await loadBlog(path.resolve(siteDir, 'blog')); + await generate( + 'blogMetadata.js', + `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( + blogMetadata, null, 2 )};\n` @@ -32,14 +46,13 @@ module.exports = async function load(siteDir) { ? path.resolve(__dirname, '../ui') : siteConfig.uiPath; - const publicPath = siteConfig.base || '/'; + const baseUrl = siteConfig.baseUrl || '/'; return { siteConfig, - blogDatas, siteDir, outDir, uiPath, - publicPath + baseUrl }; }; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 29bffe0567..b84a05d719 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -2,7 +2,7 @@ const Config = require('webpack-chain'); const path = require('path'); module.exports = function createBaseConfig(props) { - const {outDir, uiPath, siteDir, publicPath} = props; + const {outDir, uiPath, siteDir, baseUrl} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -13,7 +13,7 @@ module.exports = function createBaseConfig(props) { .filename( isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' ) - .publicPath(isProd ? publicPath : '/'); + .publicPath(isProd ? baseUrl : '/'); config.resolve .set('symlinks', true) diff --git a/package.json b/package.json index 4218cdff92..374f2436dd 100644 --- a/package.json +++ b/package.json @@ -51,15 +51,18 @@ "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", + "highlight.js": "^9.12.0", "html-webpack-plugin": "^3.2.0", "koa-connect": "^2.0.1", "koa-mount": "^3.0.0", "koa-range": "^0.3.0", "koa-static": "^5.0.0", "portfinder": "^1.0.13", + "prismjs": "^1.15.0", "react": "^16.4.1", "react-dom": "^16.4.1", "react-router-dom": "^4.3.1", + "remarkable": "^1.7.1", "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", diff --git a/yarn.lock b/yarn.lock index 88553e302e..31940932f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -379,6 +379,13 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@~0.1.15: + version "0.1.16" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" + dependencies: + underscore "~1.7.0" + underscore.string "~2.4.0" + aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" @@ -517,6 +524,10 @@ atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" +autolinker@~0.15.0: + version "0.15.3" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -1492,6 +1503,14 @@ cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" +clipboard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.1.tgz#a12481e1c13d8a50f5f036b0560fe5d16d74e46a" + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + clipboardy@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef" @@ -1895,6 +1914,10 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2846,6 +2869,12 @@ globby@^8.0.1: pify "^3.0.0" slash "^1.0.0" +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + dependencies: + delegate "^3.1.2" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -2970,6 +2999,10 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +highlight.js@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" + history@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" @@ -5132,6 +5165,12 @@ pretty-time@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" +prismjs@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9" + optionalDependencies: + clipboard "^2.0.0" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -5505,6 +5544,13 @@ relateurl@0.2.x: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" +remarkable@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6" + dependencies: + argparse "~0.1.15" + autolinker "~0.15.0" + remove-array-items@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/remove-array-items/-/remove-array-items-1.0.0.tgz#07bf42cb332f4cf6e85ead83b5e4e896d2326b21" @@ -5737,6 +5783,10 @@ schema-utils@^0.4.4, schema-utils@^0.4.5: ajv "^6.1.0" ajv-keywords "^3.1.0" +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -6211,6 +6261,10 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tiny-emitter@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6361,6 +6415,14 @@ uglifyjs-webpack-plugin@^1.2.4: webpack-sources "^1.1.0" worker-farm "^1.5.2" +underscore.string@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" + +underscore@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" From dc1e417db84eaff6f2e9856da08492fe45a937aa Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 19:51:08 +0800 Subject: [PATCH 035/135] fix: blog file should trigger reload --- docs/docusaurus.md | 26 ++++++++++++++++++++++++++ docs/intro.md | 6 ------ lib/commands/start.js | 12 ++++++++---- lib/loader/blog.js | 8 ++++---- 4 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 docs/docusaurus.md delete mode 100644 docs/intro.md diff --git a/docs/docusaurus.md b/docs/docusaurus.md new file mode 100644 index 0000000000..97487e4000 --- /dev/null +++ b/docs/docusaurus.md @@ -0,0 +1,26 @@ +--- +id: docusaurus +title: docusaurus +--- + +

+

Docusaurus

+ Docusaurus +

+ +

+ npm version + CircleCI Status + PRs Welcome + Chat + code style: prettier + Tested with Jest +

+ +## Introduction + +Docusaurus is a project for easily building, deploying, and maintaining open source project websites. + +* **Simple to Start** Docusaurus is built to be easy to [get up and running](https://docusaurus.io/docs/en/installation.html) in as little time possible. We've built Docusaurus to handle the website build process so you can focus on your project. +* **Localizable** Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation.html) via CrowdIn. Empower and grow your international community by translating your documentation. +* **Customizable** While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/blog.html), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages.html) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages.html). \ No newline at end of file diff --git a/docs/intro.md b/docs/intro.md deleted file mode 100644 index b420713204..0000000000 --- a/docs/intro.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: intro -title: Introducing Munseo ---- - -Introducing Munseo :) \ No newline at end of file diff --git a/lib/commands/start.js b/lib/commands/start.js index 284bd45543..8597da303d 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -31,10 +31,14 @@ module.exports = async function start(siteDir, cliOptions = {}) { console.error(chalk.red(err.stack)); }); }; - const fsWatcher = chokidar.watch(['../docs/**/*.md', 'siteConfig.js'], { - cwd: siteDir, - ignoreInitial: true - }); + const docsRelativeDir = props.siteConfig.customDocsPath || 'docs'; + const fsWatcher = chokidar.watch( + [`../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', 'siteConfig.js'], + { + cwd: siteDir, + ignoreInitial: true + } + ); fsWatcher.on('add', reload); fsWatcher.on('change', reload); fsWatcher.on('unlink', reload); diff --git a/lib/loader/blog.js b/lib/loader/blog.js index da54415a74..7d5704d53d 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -22,14 +22,14 @@ function parse(fileString) { return {metadata, content}; } -async function loadBlog(siteDir) { - const blogFiles = await globby(['**/*.md', '!.munseo', '!node_modules'], { - cwd: siteDir +async function loadBlog(blogDir) { + const blogFiles = await globby(['**/*.md'], { + cwd: blogDir }); const blogDatas = await Promise.all( blogFiles.map(async file => { - const filepath = path.resolve(siteDir, file); + const filepath = path.resolve(blogDir, file); const fileString = await fs.readFile(filepath, 'utf-8'); const {metadata, content} = parse(fileString); From 36eee2941ae94954d41fa6b1f48226f2d96586d6 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 19:51:22 +0800 Subject: [PATCH 036/135] feat: add home page for available routes --- lib/core/devEntry.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js index ebf7322b07..c90d9f6619 100644 --- a/lib/core/devEntry.js +++ b/lib/core/devEntry.js @@ -15,12 +15,31 @@ const renderDocs = props => { return ; }; +const Home = () => { + const showLink = path => ( +
  • + {path} +
  • + ); + const blogLinks = blogMetadata.map(blog => showLink(blog.path)); + const docsLinks = docsMetadata.map(doc => showLink(doc.path)); + + return ( +
      + {'Available Routes'} + {blogLinks} + {docsLinks} +
    + ); +}; + class App extends React.Component { render() { return (
    + {blogMetadata.map(({path, content}) => ( ))} From 9fef99cb189497a2a983eb14ab0afb06facf27fc Mon Sep 17 00:00:00 2001 From: endiliey Date: Tue, 7 Aug 2018 00:41:05 +0800 Subject: [PATCH 037/135] refactor: rename loader to load as not to confuse webpack loader --- lib/commands/start.js | 2 +- lib/{loader => load}/blog.js | 2 +- lib/{loader => load}/config.js | 0 lib/{loader => load}/docs.js | 3 +- lib/{loader => load}/index.js | 0 test/loader/__fixtures__/custom/config.js | 6 --- test/loader/__fixtures__/custom/foo/bar.md | 6 --- test/loader/__fixtures__/custom/foo/baz.md | 5 -- test/loader/__fixtures__/custom/hello.md | 6 --- test/loader/__fixtures__/simple/config.js | 4 -- test/loader/__fixtures__/simple/hello.md | 6 --- test/loader/__snapshots__/blog.test.js.snap | 46 ------------------- test/loader/__snapshots__/config.test.js.snap | 17 ------- test/loader/blog.test.js | 17 ------- test/loader/config.test.js | 15 ------ 15 files changed, 4 insertions(+), 131 deletions(-) rename lib/{loader => load}/blog.js (94%) rename lib/{loader => load}/config.js (100%) rename lib/{loader => load}/docs.js (90%) rename lib/{loader => load}/index.js (100%) delete mode 100644 test/loader/__fixtures__/custom/config.js delete mode 100644 test/loader/__fixtures__/custom/foo/bar.md delete mode 100644 test/loader/__fixtures__/custom/foo/baz.md delete mode 100644 test/loader/__fixtures__/custom/hello.md delete mode 100644 test/loader/__fixtures__/simple/config.js delete mode 100644 test/loader/__fixtures__/simple/hello.md delete mode 100644 test/loader/__snapshots__/blog.test.js.snap delete mode 100644 test/loader/__snapshots__/config.test.js.snap delete mode 100644 test/loader/blog.test.js delete mode 100644 test/loader/config.test.js diff --git a/lib/commands/start.js b/lib/commands/start.js index 8597da303d..fa26169e3f 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -12,7 +12,7 @@ const portfinder = require('portfinder'); const serve = require('webpack-serve'); const webpackNiceLog = require('webpack-nicelog'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const load = require('../loader'); +const load = require('../load'); const createDevConfig = require('../webpack/dev'); async function getPort(port) { diff --git a/lib/loader/blog.js b/lib/load/blog.js similarity index 94% rename from lib/loader/blog.js rename to lib/load/blog.js index 7d5704d53d..c2dccf848d 100644 --- a/lib/loader/blog.js +++ b/lib/load/blog.js @@ -10,7 +10,7 @@ function fileToPath(file) { if (indexRE.test(file)) { return file.replace(indexRE, '/$1'); } - return `/${file.replace(mdRE, '').replace(/\\/g, '/')}.html`; + return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; } function parse(fileString) { diff --git a/lib/loader/config.js b/lib/load/config.js similarity index 100% rename from lib/loader/config.js rename to lib/load/config.js diff --git a/lib/loader/docs.js b/lib/load/docs.js similarity index 90% rename from lib/loader/docs.js rename to lib/load/docs.js index a117b5deeb..d5dfa0e7ce 100644 --- a/lib/loader/docs.js +++ b/lib/load/docs.js @@ -10,7 +10,7 @@ function fileToPath(file) { if (indexRE.test(file)) { return file.replace(indexRE, '/$1'); } - return `/${file.replace(mdRE, '').replace(/\\/g, '/')}.html`; + return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; } function parse(fileString) { @@ -22,6 +22,7 @@ function parse(fileString) { return {metadata, content}; } +// still TODO. still copy paste from blog logic async function loadDocs(siteDir) { const blogFiles = await globby(['**/*.md'], { cwd: siteDir diff --git a/lib/loader/index.js b/lib/load/index.js similarity index 100% rename from lib/loader/index.js rename to lib/load/index.js diff --git a/test/loader/__fixtures__/custom/config.js b/test/loader/__fixtures__/custom/config.js deleted file mode 100644 index 0c4661619e..0000000000 --- a/test/loader/__fixtures__/custom/config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - title: 'Hello World', - description: 'Hello World', - dest: 'blogi', - base: 'blogi' -}; diff --git a/test/loader/__fixtures__/custom/foo/bar.md b/test/loader/__fixtures__/custom/foo/bar.md deleted file mode 100644 index ba294597fd..0000000000 --- a/test/loader/__fixtures__/custom/foo/bar.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Lorem ipsum -date: 2018-06-20 ---- - -Lorem ipsum diff --git a/test/loader/__fixtures__/custom/foo/baz.md b/test/loader/__fixtures__/custom/foo/baz.md deleted file mode 100644 index c4e0cbf40d..0000000000 --- a/test/loader/__fixtures__/custom/foo/baz.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Baz -date: 2018-05-20 ---- -Life is so good diff --git a/test/loader/__fixtures__/custom/hello.md b/test/loader/__fixtures__/custom/hello.md deleted file mode 100644 index 6d86ef4978..0000000000 --- a/test/loader/__fixtures__/custom/hello.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Hello, World ! -date: 2018-07-28 ---- - -Hello World diff --git a/test/loader/__fixtures__/simple/config.js b/test/loader/__fixtures__/simple/config.js deleted file mode 100644 index 22d383d3c4..0000000000 --- a/test/loader/__fixtures__/simple/config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - title: 'Hello World', - description: 'Hello World' -}; diff --git a/test/loader/__fixtures__/simple/hello.md b/test/loader/__fixtures__/simple/hello.md deleted file mode 100644 index 6d86ef4978..0000000000 --- a/test/loader/__fixtures__/simple/hello.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Hello, World ! -date: 2018-07-28 ---- - -Hello World diff --git a/test/loader/__snapshots__/blog.test.js.snap b/test/loader/__snapshots__/blog.test.js.snap deleted file mode 100644 index 04dd3fe1ad..0000000000 --- a/test/loader/__snapshots__/blog.test.js.snap +++ /dev/null @@ -1,46 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loadBlog custom 1`] = ` -Array [ - Object { - "content": " - -Hello World -", - "date": 2018-07-28T00:00:00.000Z, - "path": "/hello.html", - "title": "Hello, World !", - }, - Object { - "content": " - -Lorem ipsum -", - "date": 2018-06-20T00:00:00.000Z, - "path": "/foo/bar.html", - "title": "Lorem ipsum", - }, - Object { - "content": " -Life is so good -", - "date": 2018-05-20T00:00:00.000Z, - "path": "/foo/baz.html", - "title": "Baz", - }, -] -`; - -exports[`loadBlog simple 1`] = ` -Array [ - Object { - "content": " - -Hello World -", - "date": 2018-07-28T00:00:00.000Z, - "path": "/hello.html", - "title": "Hello, World !", - }, -] -`; diff --git a/test/loader/__snapshots__/config.test.js.snap b/test/loader/__snapshots__/config.test.js.snap deleted file mode 100644 index 21049a5948..0000000000 --- a/test/loader/__snapshots__/config.test.js.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loadConfig custom 1`] = ` -Object { - "base": "blogi", - "description": "Hello World", - "dest": "blogi", - "title": "Hello World", -} -`; - -exports[`loadConfig simple 1`] = ` -Object { - "description": "Hello World", - "title": "Hello World", -} -`; diff --git a/test/loader/blog.test.js b/test/loader/blog.test.js deleted file mode 100644 index 28f61e0b90..0000000000 --- a/test/loader/blog.test.js +++ /dev/null @@ -1,17 +0,0 @@ -const path = require('path'); -const loadBlog = require('../../lib/loader/blog'); - -describe('loadBlog', () => { - const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); - const customDir = path.join(__dirname, '__fixtures__', 'custom'); - - test('simple', async () => { - const blogDatas = await loadBlog(simpleDir); - expect(blogDatas).toMatchSnapshot(); - }); - - test('custom', async () => { - const blogDatas = await loadBlog(customDir); - expect(blogDatas).toMatchSnapshot(); - }); -}); diff --git a/test/loader/config.test.js b/test/loader/config.test.js deleted file mode 100644 index f1b137dbdf..0000000000 --- a/test/loader/config.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const path = require('path'); -const loadConfig = require('../../lib/loader/config'); - -describe('loadConfig', () => { - const simpleDir = path.join(__dirname, '__fixtures__', 'simple'); - const customDir = path.join(__dirname, '__fixtures__', 'custom'); - - test('simple', () => { - expect(loadConfig(simpleDir)).toMatchSnapshot(); - }); - - test('custom', () => { - expect(loadConfig(customDir)).toMatchSnapshot(); - }); -}); From e85d3230a9e3ced1d865eb623092e36cf8bdd022 Mon Sep 17 00:00:00 2001 From: endiliey Date: Tue, 7 Aug 2018 18:13:42 +0800 Subject: [PATCH 038/135] feat: add very simple default theme --- lib/theme/Docs.js | 8 ++++++++ lib/theme/Layout.js | 7 +++++++ lib/theme/NotFound.js | 15 +++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 lib/theme/Docs.js create mode 100644 lib/theme/Layout.js create mode 100644 lib/theme/NotFound.js diff --git a/lib/theme/Docs.js b/lib/theme/Docs.js new file mode 100644 index 0000000000..ac697dde59 --- /dev/null +++ b/lib/theme/Docs.js @@ -0,0 +1,8 @@ +import React from 'react'; +import Layout from '@theme/Layout'; + +export default class Docs extends React.Component { + render() { + return {this.props.children}; + } +} diff --git a/lib/theme/Layout.js b/lib/theme/Layout.js new file mode 100644 index 0000000000..f1dafba2e5 --- /dev/null +++ b/lib/theme/Layout.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export default class Layout extends React.Component { + render() { + return
    {this.props.children}
    ; + } +} diff --git a/lib/theme/NotFound.js b/lib/theme/NotFound.js new file mode 100644 index 0000000000..b8234a0422 --- /dev/null +++ b/lib/theme/NotFound.js @@ -0,0 +1,15 @@ +import React from 'react'; +import Layout from '@theme/Layout'; + +export default class NotFound extends React.Component { + render() { + return ( + +
    404 Page Not Found
    +
    + +
    +
    + ); + } +} From e64a06c7483dd35d4a571eb98c49ca64742b5931 Mon Sep 17 00:00:00 2001 From: endiliey Date: Tue, 7 Aug 2018 18:15:12 +0800 Subject: [PATCH 039/135] feat: simple webpack config --- lib/webpack/config/base.js | 48 ++++++++++++++++++++++++++++++++++++++ lib/webpack/config/dev.js | 10 ++++++++ lib/webpack/config/prod.js | 12 ++++++++++ 3 files changed, 70 insertions(+) create mode 100644 lib/webpack/config/base.js create mode 100644 lib/webpack/config/dev.js create mode 100644 lib/webpack/config/prod.js diff --git a/lib/webpack/config/base.js b/lib/webpack/config/base.js new file mode 100644 index 0000000000..6f74fa8627 --- /dev/null +++ b/lib/webpack/config/base.js @@ -0,0 +1,48 @@ +const Config = require('webpack-chain'); +const path = require('path'); + +module.exports = function createBaseConfig(props) { + const {outDir, themePath, siteDir, baseUrl} = props; + + const config = new Config(); + const isProd = process.env.NODE_ENV === 'production'; + + config + .mode(isProd ? 'production' : 'development') + .output.path(outDir) + .filename( + isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' + ) + .publicPath(isProd ? baseUrl : '/'); + + config.resolve + .set('symlinks', true) + .alias.set('@theme', themePath) + .set('@site', siteDir) + .set('@generated', path.resolve(__dirname, '../core/generated')) + .set('@core', path.resolve(__dirname, '../core')) + .end(); + + const libDir = path.join(__dirname, '..'); + config.module + .rule('js') + .test(/\.js$/) + .exclude.add(filepath => { + // Always transpile lib directory + if (filepath.startsWith(libDir)) { + return false; + } + // Don't transpile node_modules + return /node_modules/.test(filepath); + }) + .end() + .use('babel') + .loader('babel-loader') + .options({ + // do not pick local project babel config + babelrc: false, + presets: ['env', 'react'] + }); + + return config; +}; diff --git a/lib/webpack/config/dev.js b/lib/webpack/config/dev.js new file mode 100644 index 0000000000..58613caf85 --- /dev/null +++ b/lib/webpack/config/dev.js @@ -0,0 +1,10 @@ +const path = require('path'); +const createBaseConfig = require('./base'); + +module.exports = function createDevConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); + + return config; +}; diff --git a/lib/webpack/config/prod.js b/lib/webpack/config/prod.js new file mode 100644 index 0000000000..3d33eb740b --- /dev/null +++ b/lib/webpack/config/prod.js @@ -0,0 +1,12 @@ +const path = require('path'); +const createBaseConfig = require('./base'); + +module.exports = function createProdConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/prodEntry.js')); + + // TODO + + return config; +}; From 698e09b82ec2ef1d455d943ea6157361b05fea9b Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:37:14 +0800 Subject: [PATCH 040/135] chore: dotfiles --- .eslintignore | 1 + .eslintrc.js | 2 ++ .gitignore | 1 + 3 files changed, 4 insertions(+) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..dc9b2375c7 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +generated \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 6f297e956d..a107847819 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,6 +15,8 @@ module.exports = { 'func-names': OFF, 'react/jsx-filename-extension': OFF, 'react/jsx-one-expression-per-line': OFF, + 'react/prop-types': OFF, + 'react/destructuring-assignment': OFF, // too many lines 'import/no-unresolved': WARNING, // because it couldn't resolve webpack alias 'react/prefer-stateless-function': WARNING, }, diff --git a/.gitignore b/.gitignore index 21ee9db9eb..6ec778063d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist yarn-error.log generated website/node_modules +build From d582895c6f7cb02df13cea18241970b4a0978f4e Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:37:25 +0800 Subject: [PATCH 041/135] chore: dependencies --- package.json | 3 ++ yarn.lock | 140 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 137 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 374f2436dd..cb69e0c103 100644 --- a/package.json +++ b/package.json @@ -57,13 +57,16 @@ "koa-mount": "^3.0.0", "koa-range": "^0.3.0", "koa-static": "^5.0.0", + "loader-utils": "^1.1.0", "portfinder": "^1.0.13", "prismjs": "^1.15.0", "react": "^16.4.1", "react-dom": "^16.4.1", + "react-router-config": "^1.0.0-beta.4", "react-router-dom": "^4.3.1", "remarkable": "^1.7.1", "semver": "^5.5.0", + "static-site-generator-webpack-plugin": "^3.4.1", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", "webpack-nicelog": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 31940932f2..2252a088cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1141,7 +1141,7 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" -bluebird@^3.5.1: +bluebird@^3.0.5, bluebird@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -1430,6 +1430,27 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + chokidar@^2.0.2, chokidar@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -1756,7 +1777,7 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" -css-select@^1.1.0: +css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" dependencies: @@ -1996,7 +2017,7 @@ dom-converter@~0.1: dependencies: utila "~0.3" -dom-serializer@0: +dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" dependencies: @@ -2007,7 +2028,7 @@ domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" -domelementtype@1: +domelementtype@1, domelementtype@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" @@ -2027,6 +2048,12 @@ domhandler@2.1: dependencies: domelementtype "1" +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + dependencies: + domelementtype "1" + domutils@1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" @@ -2040,6 +2067,13 @@ domutils@1.5.1: dom-serializer "0" domelementtype "1" +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + dependencies: + dom-serializer "0" + domelementtype "1" + dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -2117,7 +2151,7 @@ enhanced-resolve@^4.1.0: memory-fs "^0.4.0" tapable "^1.0.0" -entities@~1.1.1: +entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" @@ -2370,6 +2404,12 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" +eval@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.2.tgz#9f7103284c105a66df4030b2b3273165837013da" + dependencies: + require-like ">= 0.1.1" + events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -3072,6 +3112,17 @@ html-webpack-plugin@^3.2.0: toposort "^1.0.0" util.promisify "1.0.0" +htmlparser2@^3.9.1: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + htmlparser2@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" @@ -4193,10 +4244,58 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + +lodash.merge@^4.4.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -5350,6 +5449,10 @@ react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" +react-router-config@^1.0.0-beta.4: + version "1.0.0-beta.4" + resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-1.0.0-beta.4.tgz#d202496dd0eabdf06cf24eb0793031f6891eef01" + react-router-dom@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" @@ -5626,6 +5729,10 @@ require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" +"require-like@>= 0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/require-like/-/require-like-0.1.2.tgz#ad6f30c13becd797010c468afa775c0c0a6b47fa" + require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" @@ -5921,6 +6028,10 @@ sockjs-client@1.1.4: json3 "^3.3.2" url-parse "^1.1.8" +source-list-map@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1" + source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -5952,7 +6063,7 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -6030,6 +6141,16 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +static-site-generator-webpack-plugin@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-3.4.1.tgz#6ee22468830bc546798a37e0fca6fd699cc93b81" + dependencies: + bluebird "^3.0.5" + cheerio "^0.22.0" + eval "^0.1.0" + url "^0.11.0" + webpack-sources "^0.2.0" + "statuses@>= 1.4.0 < 2", statuses@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -6722,6 +6843,13 @@ webpack-serve@^2.0.2: v8-compile-cache "^2.0.0" webpack-log "^1.1.2" +webpack-sources@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb" + dependencies: + source-list-map "^1.1.1" + source-map "~0.5.3" + webpack-sources@^1.0.1, webpack-sources@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" From f9bc0ff7b8beec158472ecc066fa84a3d66bfcc9 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:38:11 +0800 Subject: [PATCH 042/135] feat: add React component to render Markdown --- lib/core/components/Markdown/anchors.js | 22 +++++ lib/core/components/Markdown/index.js | 115 ++++++++++++++++++++++++ lib/core/components/Markdown/toSlug.js | 68 ++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 lib/core/components/Markdown/anchors.js create mode 100644 lib/core/components/Markdown/index.js create mode 100644 lib/core/components/Markdown/toSlug.js diff --git a/lib/core/components/Markdown/anchors.js b/lib/core/components/Markdown/anchors.js new file mode 100644 index 0000000000..e62424b081 --- /dev/null +++ b/lib/core/components/Markdown/anchors.js @@ -0,0 +1,22 @@ +const toSlug = require('./toSlug.js'); + +function anchors(md) { + const originalRender = md.renderer.rules.heading_open; + + // eslint-disable-next-line + md.renderer.rules.heading_open = function(tokens, idx, options, env) { + const textToken = tokens[idx + 1]; + + if (textToken.content) { + const anchor = toSlug(textToken.content, env); + + return ``; + } + + return originalRender(tokens, idx, options, env); + }; +} + +module.exports = anchors; diff --git a/lib/core/components/Markdown/index.js b/lib/core/components/Markdown/index.js new file mode 100644 index 0000000000..8617c6bd93 --- /dev/null +++ b/lib/core/components/Markdown/index.js @@ -0,0 +1,115 @@ +/* eslint-disable react/no-danger */ + +const React = require('react'); +const Markdown = require('remarkable'); +const hljs = require('highlight.js'); +const prismjs = require('prismjs'); + +const anchors = require('./anchors.js'); + +class MarkdownBlock extends React.Component { + content() { + if (this.props.source) { + return ( + + ); + } + return React.Children.map(this.props.children, child => { + if (typeof child === 'string') { + return ( + + ); + } + return child; + }); + } + + renderMarkdown(source) { + const alias = { + js: 'jsx' + }; + const {siteConfig} = this.props; + const md = new Markdown({ + langPrefix: 'hljs css language-', + highlight(str, reqLang) { + const lang = + reqLang || (siteConfig.highlight && siteConfig.highlight.defaultLang); + if (lang === 'text') { + return str; + } + if (lang) { + try { + if ( + siteConfig.usePrism === true || + (siteConfig.usePrism && + siteConfig.usePrism.length > 0 && + siteConfig.usePrism.indexOf(lang) !== -1) + ) { + try { + const language = alias[lang] || lang; + // Currently people using prismjs on Node have to individually require() + // every single language (https://github.com/PrismJS/prism/issues/593) + require(`prismjs/components/prism-${language}.min`); // eslint-disable-line + return prismjs.highlight(str, prismjs.languages[language]); + } catch (err) { + console.error(err); + } + } + if (hljs.getLanguage(lang)) { + return hljs.highlight(lang, str).value; + } + } catch (err) { + console.error(err); + } + } + + try { + return hljs.highlightAuto(str).value; + } catch (err) { + console.error(err); + } + + return ''; + }, + html: true, + linkify: true + }); + + // Register anchors plugin + md.use(anchors); + + // Allow client sites to register their own plugins + if (siteConfig.markdownPlugins) { + siteConfig.markdownPlugins.forEach(plugin => { + md.use(plugin); + }); + } + + const html = md.render(source); + + // Ensure fenced code blocks use Highlight.js hljs class + // https://github.com/jonschlinkert/remarkable/issues/224 + return html.replace(/
    /g, '
    ');
    +  }
    +
    +  render() {
    +    const Container = this.props.container;
    +    if (!Container) {
    +      return 
    {this.content()}
    ; + } + return {this.content()}; + } +} + +MarkdownBlock.defaultProps = { + container: 'div', + siteConfig: {} +}; + +export default MarkdownBlock; diff --git a/lib/core/components/Markdown/toSlug.js b/lib/core/components/Markdown/toSlug.js new file mode 100644 index 0000000000..13bf572596 --- /dev/null +++ b/lib/core/components/Markdown/toSlug.js @@ -0,0 +1,68 @@ +/* eslint-disable */ + +const letters = + '\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'; +const numbers = + '\u0030-\u0039\u00B2\u00B3\u00B9\u00BC-\u00BE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19'; +const exceptAlphanum = new RegExp(`[^${[letters, numbers].join('')}]`, 'g'); + +/** + * Converts a string to a slug, that can be used in heading anchors + * + * @param {string} string + * @param {Object} [context={}] - an optional context to track used slugs and + * ensure that new slug will be unique + * + * @return {string} + */ +module.exports = (string, context = {}) => { + // var accents = "àáäâèéëêìíïîòóöôùúüûñç"; + const accents = + '\u00e0\u00e1\u00e4\u00e2\u00e8' + + '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' + + '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' + + '\u00fa\u00fc\u00fb\u00f1\u00e7'; + + const without = 'aaaaeeeeiiiioooouuuunc'; + + let slug = string + .toString() + // Handle uppercase characters + .toLowerCase() + // Handle accentuated characters + .replace(new RegExp(`[${accents}]`, 'g'), c => + without.charAt(accents.indexOf(c)) + ) + // Replace `.`, `(` and `?` with blank string like Github does + .replace(/\.|\(|\?/g, '') + // Dash special characters + .replace(exceptAlphanum, '-') + // Compress multiple dash + .replace(/-+/g, '-') + // Trim dashes + .replace(/^-|-$/g, ''); + + // Add trailing `-` if string contains ` ...` in the end like Github does + if (/\s[.]{1,}/.test(string)) { + slug += '-'; + } + + if (!context.slugStats) { + context.slugStats = {}; + } + + if (typeof context.slugStats[slug] === 'number') { + // search for an index, that will not clash with an existing headings + while ( + typeof context.slugStats[`${slug}-${++context.slugStats[slug]}`] === + 'number' + ); + slug += `-${context.slugStats[slug]}`; + } + + // we are tracking both original anchors and suffixed to avoid future name + // clashing with headings with numbers e.g. `#Foo 1` may clash with the second `#Foo` + context.slugStats[slug] = 0; + + return slug; +}; From 9e7729ad748fe08c196cb4b74100064070646ab2 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:39:17 +0800 Subject: [PATCH 043/135] feat: react router config generation for docs --- lib/load/blog.js | 47 ----------------------------------- lib/load/docs.js | 33 +++++++++---------------- lib/load/index.js | 61 ++++++++++++++++++++-------------------------- lib/load/routes.js | 38 +++++++++++++++++++++++++++++ lib/load/utils.js | 48 ++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 103 deletions(-) delete mode 100644 lib/load/blog.js create mode 100644 lib/load/routes.js create mode 100644 lib/load/utils.js diff --git a/lib/load/blog.js b/lib/load/blog.js deleted file mode 100644 index c2dccf848d..0000000000 --- a/lib/load/blog.js +++ /dev/null @@ -1,47 +0,0 @@ -const fs = require('fs-extra'); -const path = require('path'); -const fm = require('front-matter'); -const globby = require('globby'); - -const indexRE = /(^|.*\/)index\.md$/i; -const mdRE = /\.md$/; - -function fileToPath(file) { - if (indexRE.test(file)) { - return file.replace(indexRE, '/$1'); - } - return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; -} - -function parse(fileString) { - if (!fm.test(fileString)) { - return {metadata: null, content: fileString}; - } - const {attributes: metadata, body: content} = fm(fileString); - - return {metadata, content}; -} - -async function loadBlog(blogDir) { - const blogFiles = await globby(['**/*.md'], { - cwd: blogDir - }); - - const blogDatas = await Promise.all( - blogFiles.map(async file => { - const filepath = path.resolve(blogDir, file); - const fileString = await fs.readFile(filepath, 'utf-8'); - const {metadata, content} = parse(fileString); - - return { - path: fileToPath(file), - content, - ...metadata - }; - }) - ); - blogDatas.sort((a, b) => b.date - a.date); - return blogDatas; -} - -module.exports = loadBlog; diff --git a/lib/load/docs.js b/lib/load/docs.js index d5dfa0e7ce..7483b9d2e7 100644 --- a/lib/load/docs.js +++ b/lib/load/docs.js @@ -2,16 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const fm = require('front-matter'); const globby = require('globby'); - -const indexRE = /(^|.*\/)index\.md$/i; -const mdRE = /\.md$/; - -function fileToPath(file) { - if (indexRE.test(file)) { - return file.replace(indexRE, '/$1'); - } - return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; -} +const {encodePath, fileToPath} = require('./utils'); function parse(fileString) { if (!fm.test(fileString)) { @@ -22,27 +13,25 @@ function parse(fileString) { return {metadata, content}; } -// still TODO. still copy paste from blog logic -async function loadDocs(siteDir) { - const blogFiles = await globby(['**/*.md'], { - cwd: siteDir +async function loadDocs(docsDir) { + const docsFiles = await globby(['**/*.md'], { + cwd: docsDir }); - const blogDatas = await Promise.all( - blogFiles.map(async file => { - const filepath = path.resolve(siteDir, file); + const docsData = await Promise.all( + docsFiles.map(async source => { + const filepath = path.resolve(docsDir, source); const fileString = await fs.readFile(filepath, 'utf-8'); - const {metadata, content} = parse(fileString); + const {metadata} = parse(fileString); return { - path: fileToPath(file), - content, + path: encodePath(fileToPath(source)), + source, ...metadata }; }) ); - blogDatas.sort((a, b) => b.date - a.date); - return blogDatas; + return docsData; } module.exports = loadDocs; diff --git a/lib/load/index.js b/lib/load/index.js index cd56932b5a..c1729f2251 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -1,58 +1,51 @@ const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); -const loadBlog = require('./blog'); const loadDocs = require('./docs'); -const {generate} = require('../helpers'); +const {generate} = require('./utils'); +const genRoutesConfig = require('./routes'); module.exports = async function load(siteDir) { - // load siteConfig + // siteConfig const siteConfig = loadConfig(siteDir); // docs - const docsRelativeDir = siteConfig.customDocsPath || 'docs'; - const docsMetadata = await loadDocs( - path.resolve(siteDir, '..', docsRelativeDir) + const docsDir = path.resolve( + siteDir, + '..', + siteConfig.customDocsPath || 'docs' ); + const docsData = await loadDocs(docsDir); await generate( - 'docsMetadata.js', - `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( - docsMetadata, - null, - 2 - )};\n` - ); - - // blog - const blogMetadata = await loadBlog(path.resolve(siteDir, 'blog')); - await generate( - 'blogMetadata.js', - `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( - blogMetadata, - null, - 2 - )};\n` + 'docsData.js', + `export const docsData = ${JSON.stringify(docsData, null, 2)}` ); // resolve outDir - const outDir = siteConfig.dest - ? path.resolve(siteConfig.dest) - : path.resolve(siteDir, '.munseo/dist'); + const outDir = path.resolve(siteDir, 'build'); - // resolve the path of our app user interface layout - const uiPath = - !siteConfig.uiPath || - !fs.existsSync(path.resolve(siteDir, siteConfig.uiPath)) - ? path.resolve(__dirname, '../ui') - : siteConfig.uiPath; + // resolve the theme + const themePath = + siteConfig.themePath && + fs.existsSync(path.resolve(siteDir, siteConfig.themePath)) + ? siteConfig.themePath + : path.resolve(__dirname, '../theme'); const baseUrl = siteConfig.baseUrl || '/'; - return { + const props = { siteConfig, siteDir, + docsDir, + docsData, outDir, - uiPath, + themePath, baseUrl }; + + // Generate React Router Config + const routesConfig = await genRoutesConfig(props); + await generate('routes.js', routesConfig); + + return props; }; diff --git a/lib/load/routes.js b/lib/load/routes.js new file mode 100644 index 0000000000..1482b66ba9 --- /dev/null +++ b/lib/load/routes.js @@ -0,0 +1,38 @@ +const path = require('path'); +const {fileToComponentName} = require('./utils'); + +async function genRoutesConfig({docsData, docsDir}) { + function genDocsRoute({path: docsPath, source}) { + const componentName = fileToComponentName(source); + return ` + { + path: ${JSON.stringify(docsPath)}, + component: () => <${componentName} /> + }`; + } + + function genDocsImport({source}) { + const filePath = path.resolve(docsDir, source); + const componentName = fileToComponentName(source); + return `import ${componentName} from ${JSON.stringify(filePath)}`; + } + + const notFoundRoute = `, + { + path: '*', + component: NotFound + }`; + + return ( + `import React from 'react';\n` + + `import Docs from '@theme/Docs';\n` + + `import NotFound from '@theme/NotFound';\n` + + `${docsData.map(genDocsImport).join('\n')}\n` + + `const routes = [${docsData + .map(genDocsRoute) + .join(',')}${notFoundRoute}\n];\n` + + `export default routes;\n` + ); +} + +module.exports = genRoutesConfig; diff --git a/lib/load/utils.js b/lib/load/utils.js new file mode 100644 index 0000000000..1163c886bf --- /dev/null +++ b/lib/load/utils.js @@ -0,0 +1,48 @@ +const path = require('path'); +const fs = require('fs-extra'); + +const genPath = path.resolve(__dirname, '../core/generated'); +fs.ensureDirSync(genPath); + +const genCache = new Map(); +async function generate(file, content) { + const cached = genCache.get(file); + if (cached !== content) { + await fs.writeFile(path.join(genPath, file), content); + genCache.set(file, content); + } +} + +const indexRE = /(^|.*\/)index\.md$/i; +const mdRE = /\.md$/; + +function fileToPath(file) { + if (indexRE.test(file)) { + return file.replace(indexRE, '/$1'); + } + return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; +} + +function encodePath(userpath) { + return userpath + .split('/') + .map(item => encodeURIComponent(item)) + .join('/'); +} + +function fileToComponentName(file) { + let str = file.replace(/([A-Z])/g, ' $1'); + if (str.length === 1) { + return str.toUpperCase(); + } + str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); + str = str.charAt(0).toUpperCase() + str.slice(1); + return str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase()); +} + +module.exports = { + encodePath, + generate, + fileToPath, + fileToComponentName +}; From 2a7f7e2663550d7d2f3f3644170811815ddb1b0e Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:39:40 +0800 Subject: [PATCH 044/135] chore: eslint fix --- lib/theme/Layout.js | 3 ++- lib/theme/NotFound.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/theme/Layout.js b/lib/theme/Layout.js index f1dafba2e5..3ba873691e 100644 --- a/lib/theme/Layout.js +++ b/lib/theme/Layout.js @@ -2,6 +2,7 @@ import React from 'react'; export default class Layout extends React.Component { render() { - return
    {this.props.children}
    ; + const {children} = this.props; + return
    {children}
    ; } } diff --git a/lib/theme/NotFound.js b/lib/theme/NotFound.js index b8234a0422..74abb1c7e7 100644 --- a/lib/theme/NotFound.js +++ b/lib/theme/NotFound.js @@ -7,7 +7,7 @@ export default class NotFound extends React.Component {
    404 Page Not Found
    - + Not found
    ); From 10f85696d9f3a67efede5da27cc6cbebbc33867e Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:40:42 +0800 Subject: [PATCH 045/135] feat: add own webpack markdown to react loader --- lib/webpack/loader/markdown.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/webpack/loader/markdown.js diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js new file mode 100644 index 0000000000..7cf53f1ccc --- /dev/null +++ b/lib/webpack/loader/markdown.js @@ -0,0 +1,19 @@ +const {getOptions} = require('loader-utils'); +const fm = require('front-matter'); +// const MarkdownBlock = require('../../core/components/markdown'); + +module.exports = function(fileString) { + const options = getOptions(this); + + const {body} = fm(fileString); + const source = JSON.stringify(body); + const siteConfig = JSON.stringify(options.siteConfig); + + return ( + `import React from 'react';\n` + + `import MarkdownBlock from '@core/components/Markdown'\n` + + `export default () => ;` + ); + + // return `export default () => `; +}; From b0f884e8430f230e763d7bac0853fdb0e330d593 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:41:19 +0800 Subject: [PATCH 046/135] feat: webpack config creator --- lib/webpack/base.js | 49 ++++++++++++++++++++++++-------------- lib/webpack/config/base.js | 48 ------------------------------------- lib/webpack/config/dev.js | 10 -------- lib/webpack/config/prod.js | 12 ---------- lib/webpack/dev.js | 20 ++++++++-------- lib/webpack/prod.js | 32 +++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 98 deletions(-) delete mode 100644 lib/webpack/config/base.js delete mode 100644 lib/webpack/config/dev.js delete mode 100644 lib/webpack/config/prod.js create mode 100644 lib/webpack/prod.js diff --git a/lib/webpack/base.js b/lib/webpack/base.js index b84a05d719..d577671721 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -1,8 +1,10 @@ const Config = require('webpack-chain'); const path = require('path'); +const mdLoader = require.resolve('./loader/markdown'); + module.exports = function createBaseConfig(props) { - const {outDir, uiPath, siteDir, baseUrl} = props; + const {siteConfig, outDir, themePath, siteDir, baseUrl} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -10,39 +12,50 @@ module.exports = function createBaseConfig(props) { config .mode(isProd ? 'production' : 'development') .output.path(outDir) - .filename( - isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' - ) + .filename(isProd ? 'bundle.js' : '[name].js') .publicPath(isProd ? baseUrl : '/'); config.resolve .set('symlinks', true) - .alias.set('@ui', uiPath) - .set('@source', siteDir) - .set('@generated', path.resolve(__dirname, '../generated')) + .alias.set('@theme', themePath) + .set('@site', siteDir) + .set('@generated', path.resolve(__dirname, '../core/generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); - const libDir = path.join(__dirname, '..'); - config.module + function applyBabel(rule) { + rule + .use('babel') + .loader('babel-loader') + .options({ + babelrc: false, + presets: ['env', 'react'] + }); + } + + const jsRule = config.module .rule('js') .test(/\.js$/) .exclude.add(filepath => { // Always transpile lib directory - if (filepath.startsWith(libDir)) { + if (filepath.startsWith(path.join(__dirname, '..'))) { return false; } // Don't transpile node_modules return /node_modules/.test(filepath); }) - .end() - .use('babel') - .loader('babel-loader') - .options({ - // do not pick local project babel config - babelrc: false, - presets: ['env', 'react'] - }); + .end(); + + applyBabel(jsRule); + + const mdRule = config.module.rule('markdown').test(/\.md$/); + + applyBabel(mdRule); + + mdRule + .use('markdown-loader') + .loader(mdLoader) + .options({siteConfig}); return config; }; diff --git a/lib/webpack/config/base.js b/lib/webpack/config/base.js deleted file mode 100644 index 6f74fa8627..0000000000 --- a/lib/webpack/config/base.js +++ /dev/null @@ -1,48 +0,0 @@ -const Config = require('webpack-chain'); -const path = require('path'); - -module.exports = function createBaseConfig(props) { - const {outDir, themePath, siteDir, baseUrl} = props; - - const config = new Config(); - const isProd = process.env.NODE_ENV === 'production'; - - config - .mode(isProd ? 'production' : 'development') - .output.path(outDir) - .filename( - isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' - ) - .publicPath(isProd ? baseUrl : '/'); - - config.resolve - .set('symlinks', true) - .alias.set('@theme', themePath) - .set('@site', siteDir) - .set('@generated', path.resolve(__dirname, '../core/generated')) - .set('@core', path.resolve(__dirname, '../core')) - .end(); - - const libDir = path.join(__dirname, '..'); - config.module - .rule('js') - .test(/\.js$/) - .exclude.add(filepath => { - // Always transpile lib directory - if (filepath.startsWith(libDir)) { - return false; - } - // Don't transpile node_modules - return /node_modules/.test(filepath); - }) - .end() - .use('babel') - .loader('babel-loader') - .options({ - // do not pick local project babel config - babelrc: false, - presets: ['env', 'react'] - }); - - return config; -}; diff --git a/lib/webpack/config/dev.js b/lib/webpack/config/dev.js deleted file mode 100644 index 58613caf85..0000000000 --- a/lib/webpack/config/dev.js +++ /dev/null @@ -1,10 +0,0 @@ -const path = require('path'); -const createBaseConfig = require('./base'); - -module.exports = function createDevConfig(props) { - const config = createBaseConfig(props); - - config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); - - return config; -}; diff --git a/lib/webpack/config/prod.js b/lib/webpack/config/prod.js deleted file mode 100644 index 3d33eb740b..0000000000 --- a/lib/webpack/config/prod.js +++ /dev/null @@ -1,12 +0,0 @@ -const path = require('path'); -const createBaseConfig = require('./base'); - -module.exports = function createProdConfig(props) { - const config = createBaseConfig(props); - - config.entry('main').add(path.resolve(__dirname, '../core/prodEntry.js')); - - // TODO - - return config; -}; diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js index 58613caf85..97e42404b0 100644 --- a/lib/webpack/dev.js +++ b/lib/webpack/dev.js @@ -1,10 +1,10 @@ -const path = require('path'); -const createBaseConfig = require('./base'); - -module.exports = function createDevConfig(props) { - const config = createBaseConfig(props); - - config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); - - return config; -}; +const path = require('path'); +const createBaseConfig = require('./base'); + +module.exports = function createDevConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); + + return config; +}; diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js new file mode 100644 index 0000000000..0bca7e7345 --- /dev/null +++ b/lib/webpack/prod.js @@ -0,0 +1,32 @@ +const path = require('path'); +const staticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin'); +const createBaseConfig = require('./base'); + +module.exports = function createProdConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/prodEntry.js')); + config.output.libraryTarget('umd'); + + // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) + config.output.globalObject('this'); + + const {siteConfig, docsData} = props; + + // Find all available paths + const paths = docsData.map(docs => docs.path); + + config.plugin('StaticSiteGenerator').use(staticSiteGeneratorPlugin, [ + { + entry: 'main', + locals: { + bundlejs: 'bundle.js', + title: siteConfig.title || 'Munseo', + lang: 'en' + }, + paths + } + ]); + + return config; +}; From bc706ae33db00ba1bd66f6f8098d1acfb6c1b502 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:41:40 +0800 Subject: [PATCH 047/135] chore: eslinting --- lib/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 99577452f2..7594a1260b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,9 @@ +const build = require('./commands/build'); +const init = require('./commands/init'); +const start = require('./commands/start'); + module.exports = { - build: require('./commands/build'), - init: require('./commands/init'), - start: require('./commands/start') + build, + init, + start }; From 750804646c1a0aa2cbee64283983a1b9101be09f Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:42:21 +0800 Subject: [PATCH 048/135] feat: add App.js (react router config renderer) --- lib/core/App.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/core/App.js diff --git a/lib/core/App.js b/lib/core/App.js new file mode 100644 index 0000000000..994f141f82 --- /dev/null +++ b/lib/core/App.js @@ -0,0 +1,6 @@ +import {renderRoutes} from 'react-router-config'; + +import routes from '@generated/routes'; // eslint-disable-line +import props from '@generated/docsData'; // eslint-disable-line + +export default () => renderRoutes(routes, props); From 4c36e71d1f39614d47f1d39f87595170d9beee61 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:44:53 +0800 Subject: [PATCH 049/135] feat: add core dev files --- lib/core/devEntry.js | 61 ++++++---------------------------------- lib/core/devTemplate.ejs | 12 ++++++++ 2 files changed, 21 insertions(+), 52 deletions(-) create mode 100644 lib/core/devTemplate.ejs diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js index c90d9f6619..3cfc7386bc 100644 --- a/lib/core/devEntry.js +++ b/lib/core/devEntry.js @@ -1,55 +1,12 @@ import React from 'react'; -import {render} from 'react-dom'; -import {BrowserRouter, Route, Switch, Link} from 'react-router-dom'; -import blogMetadata from '@generated/blogMetadata'; -import docsMetadata from '@generated/docsMetadata'; -import Blog from './blog'; -import Docs from './docs'; +import ReactDOM from 'react-dom'; +import {BrowserRouter} from 'react-router-dom'; -const renderBlog = props => { - const metadata = blogMetadata.find(blog => blog.path === props.match.path); - return ; -}; -const renderDocs = props => { - const metadata = docsMetadata.find(doc => doc.path === props.match.path); - return ; -}; +import App from './App'; -const Home = () => { - const showLink = path => ( -
  • - {path} -
  • - ); - const blogLinks = blogMetadata.map(blog => showLink(blog.path)); - const docsLinks = docsMetadata.map(doc => showLink(doc.path)); - - return ( -
      - {'Available Routes'} - {blogLinks} - {docsLinks} -
    - ); -}; - -class App extends React.Component { - render() { - return ( - -
    - - - {blogMetadata.map(({path, content}) => ( - - ))} - {docsMetadata.map(({path}) => ( - - ))} - -
    -
    - ); - } -} -render(, document.getElementById('app')); +ReactDOM.render( + + + , + document.getElementById('app') +); diff --git a/lib/core/devTemplate.ejs b/lib/core/devTemplate.ejs new file mode 100644 index 0000000000..400bf45ea1 --- /dev/null +++ b/lib/core/devTemplate.ejs @@ -0,0 +1,12 @@ + + + + + + <%= htmlWebpackPlugin.options.title %> + + +
    + + + \ No newline at end of file From b079e489761170bdf172a899546f9c8ae61887da Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:45:12 +0800 Subject: [PATCH 050/135] feat: add production entry & template --- lib/core/prodEntry.js | 34 ++++++++++++++++++++++++++++++++++ lib/core/prodTemplate.js | 21 +++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 lib/core/prodEntry.js create mode 100644 lib/core/prodTemplate.js diff --git a/lib/core/prodEntry.js b/lib/core/prodEntry.js new file mode 100644 index 0000000000..60fb5a99fa --- /dev/null +++ b/lib/core/prodEntry.js @@ -0,0 +1,34 @@ +import React from 'react'; +import {BrowserRouter, StaticRouter} from 'react-router-dom'; +import ReactDOM from 'react-dom'; +import ReactDOMServer from 'react-dom/server'; + +import App from './App'; +import createHtml from './prodTemplate'; + +// Client side render (e.g: running in browser) to become single-page application (SPA) +if (typeof document !== 'undefined') { + ReactDOM.render( + + + , + document.getElementById('app') + ); +} + +// Renderer for static-site-generator-webpack-plugin (async rendering via callbacks) +export default function render(locals, callback) { + const context = {}; + const body = ReactDOMServer.renderToString( + + + + ); + const html = createHtml({ + title: locals.title, + body, + bundlejs: locals.bundlejs, + lang: locals.lang + }); + callback(null, html); +} diff --git a/lib/core/prodTemplate.js b/lib/core/prodTemplate.js new file mode 100644 index 0000000000..95f23d1bb5 --- /dev/null +++ b/lib/core/prodTemplate.js @@ -0,0 +1,21 @@ +/** + * Html + * This Html.js file acts as a template that we insert all our generated + * application code into before sending it to the client as regular HTML. + * Note we're returning a template string from this function. + */ + +module.exports = function createHtml({title, body, bundlejs, lang}) { + return ` + + + + ${title} + + +
    ${body}
    + + + + `; +}; From 7a69cff30c82c08072bfd84c347e58fd87f80994 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:45:43 +0800 Subject: [PATCH 051/135] feat: add build command --- lib/commands/build.js | 56 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/commands/build.js b/lib/commands/build.js index 0005a7c1ed..abc9be7068 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -1,6 +1,60 @@ +const webpackNiceLog = require('webpack-nicelog'); +const webpack = require('webpack'); +const path = require('path'); +const chalk = require('chalk'); +const load = require('../load'); +const createProdConfig = require('../webpack/prod'); + +function compile(config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) { + return reject(err); + } + if (stats.hasErrors()) { + stats.toJson().errors.forEach(e => { + console.error(e); + }); + reject(new Error(`Failed to compile with errors.`)); + return false; + } + if (stats.hasWarnings()) { + stats.toJson().warnings.forEach(warning => { + console.warn(warning); + }); + } + resolve(stats.toJson({modules: false})); + return true; + }); + }); +} + module.exports = async function build(siteDir, cliOptions = {}) { process.env.NODE_ENV = 'production'; console.log('Build command invoked ...'); - console.log(siteDir); console.log(cliOptions); + + const props = await load(siteDir); + + // resolve webpack config + let config = createProdConfig(props); + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ + { + name: 'Production' + } + ]); + + // create compiler from generated webpack config + config = config.toConfig(); + + // compile! + await compile(config); + + const {outDir} = props; + const relativeDir = path.relative(process.cwd(), outDir); + console.log( + `\n${chalk.green('Success!')} Generated static files in ${chalk.cyan( + relativeDir + )}.\n` + ); }; From 1150c45f9bb7e3f84114a327bc20986f7291b3b7 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:45:58 +0800 Subject: [PATCH 052/135] refactor: start cli command --- lib/commands/start.js | 229 +++++++++++++++++++++--------------------- 1 file changed, 115 insertions(+), 114 deletions(-) diff --git a/lib/commands/start.js b/lib/commands/start.js index fa26169e3f..a150ad276d 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -1,114 +1,115 @@ -const path = require('path'); -const fs = require('fs-extra'); -const chalk = require('chalk'); -const webpack = require('webpack'); -const chokidar = require('chokidar'); -const convert = require('koa-connect'); -const range = require('koa-range'); -const mount = require('koa-mount'); -const serveStatic = require('koa-static'); -const history = require('connect-history-api-fallback'); -const portfinder = require('portfinder'); -const serve = require('webpack-serve'); -const webpackNiceLog = require('webpack-nicelog'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const load = require('../load'); -const createDevConfig = require('../webpack/dev'); - -async function getPort(port) { - portfinder.basePort = parseInt(port, 10) || 3000; - return await portfinder.getPortPromise(); -} - -module.exports = async function start(siteDir, cliOptions = {}) { - // Preprocess whole files as a prop - const props = await load(siteDir); - - // (if enabled) live reload for any changes in file - if (!cliOptions.noWatch) { - const reload = () => { - load(siteDir).catch(err => { - console.error(chalk.red(err.stack)); - }); - }; - const docsRelativeDir = props.siteConfig.customDocsPath || 'docs'; - const fsWatcher = chokidar.watch( - [`../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', 'siteConfig.js'], - { - cwd: siteDir, - ignoreInitial: true - } - ); - fsWatcher.on('add', reload); - fsWatcher.on('change', reload); - fsWatcher.on('unlink', reload); - fsWatcher.on('addDir', reload); - fsWatcher.on('unlinkDir', reload); - } - - const port = await getPort(cliOptions.port); - const {baseUrl} = props; - - // resolve webpack config - let config = createDevConfig(props); - config.plugin('WebpackNiceLog').use(webpackNiceLog, [ - { - name: 'Munseo', - onDone: () => { - console.log( - `\n${chalk.blue('Development server available at ')}${chalk.cyan( - `http://localhost:${port}${baseUrl}` - )}` - ); - } - } - ]); - config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ - { - inject: false, - hash: true, - template: path.resolve(__dirname, '../core/index.html'), - filename: 'index.html' - } - ]); - - // create compiler from generated webpack config - config = config.toConfig(); - const compiler = webpack(config); - - // webpack-serve - const nonExistentDir = path.resolve(__dirname, 'non-existent'); - setTimeout(async () => { - await serve( - {}, - { - content: [nonExistentDir], - compiler, - open: false, - devMiddleware: { - logLevel: 'silent' - }, - hotClient: { - port: port + 1, - logLevel: 'error' - }, - logLevel: 'error', - port, - add: (app, middleware, options) => { - const staticDir = path.resolve(siteDir, 'static'); - if (fs.existsSync(staticDir)) { - app.use(mount(baseUrl, serveStatic(staticDir))); - } - app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 - app.use( - convert( - history({ - rewrites: [{from: /\.html$/, to: '/'}] - }) - ) - ); - } - } - ); - }, 1000); -}; +const path = require('path'); +const fs = require('fs-extra'); +const chalk = require('chalk'); +const webpack = require('webpack'); +const chokidar = require('chokidar'); +const convert = require('koa-connect'); +const range = require('koa-range'); +const mount = require('koa-mount'); +const serveStatic = require('koa-static'); +const history = require('connect-history-api-fallback'); +const portfinder = require('portfinder'); +const serve = require('webpack-serve'); +const webpackNiceLog = require('webpack-nicelog'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const load = require('../load'); +const createDevConfig = require('../webpack/dev'); + +async function getPort(reqPort) { + portfinder.basePort = parseInt(reqPort, 10) || 3000; + const port = await portfinder.getPortPromise(); + return port; +} + +module.exports = async function start(siteDir, cliOptions = {}) { + // Process all related files as a prop + const props = await load(siteDir); + + if (!cliOptions.noWatch) { + const reload = () => { + load(siteDir).catch(err => { + console.error(chalk.red(err.stack)); + }); + }; + const docsRelativeDir = props.siteConfig.customDocsPath || 'docs'; + const fsWatcher = chokidar.watch( + [`../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', 'siteConfig.js'], + { + cwd: siteDir, + ignoreInitial: true + } + ); + fsWatcher.on('add', reload); + fsWatcher.on('change', reload); + fsWatcher.on('unlink', reload); + fsWatcher.on('addDir', reload); + fsWatcher.on('unlinkDir', reload); + } + + const port = await getPort(cliOptions.port); + const {baseUrl} = props; + + // resolve webpack config + let config = createDevConfig(props); + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ + { + name: 'Munseo', + onDone: () => { + console.log( + `\n${chalk.blue('Development server available at ')}${chalk.cyan( + `http://localhost:${port}${baseUrl}` + )}` + ); + } + } + ]); + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + inject: false, + hash: true, + template: path.resolve(__dirname, '../core/devTemplate.ejs'), + filename: 'index.html', + title: props.siteConfig.title + } + ]); + + // create compiler from generated webpack config + config = config.toConfig(); + const compiler = webpack(config); + + // webpack-serve + const nonExistentDir = path.resolve(__dirname, 'non-existent'); + setTimeout(async () => { + await serve( + {}, + { + content: [nonExistentDir], + compiler, + open: false, + devMiddleware: { + logLevel: 'silent' + }, + hotClient: { + port: port + 1, + logLevel: 'error' + }, + logLevel: 'error', + port, + add: app => { + const staticDir = path.resolve(siteDir, 'static'); + if (fs.existsSync(staticDir)) { + app.use(mount(baseUrl, serveStatic(staticDir))); + } + app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 + app.use( + convert( + history({ + rewrites: [{from: /\.html$/, to: '/'}] + }) + ) + ); + } + } + ); + }, 1000); +}; From 1d99c224c013f10e4f327cc50a3a6dc24ece5675 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:46:51 +0800 Subject: [PATCH 053/135] chore: prettier & lint --- bin/munseo.js | 130 +++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/bin/munseo.js b/bin/munseo.js index 75ad89e773..b99b13ad98 100644 --- a/bin/munseo.js +++ b/bin/munseo.js @@ -1,65 +1,65 @@ -#!/usr/bin/env node - -const chalk = require('chalk'); -const semver = require('semver'); -const path = require('path'); -const program = require('commander'); -const {build, init, start} = require('../lib'); -const requiredVersion = require('../package.json').engines.node; - -if (!semver.satisfies(process.version, requiredVersion)) { - console.log( - chalk.red(`\nMinimum node version not met :)`) + - chalk.yellow( - `\nYou are using Node ${ - process.version - }, Requirement: Node ${requiredVersion}.\n` - ) - ); - process.exit(1); -} - -function wrapCommand(fn) { - return (...args) => - fn(...args).catch(err => { - console.error(chalk.red(err.stack)); - process.exitCode = 1; - }); -} - -program - .version(require('../package.json').version) - .usage(' [options]'); - -program - .command('build [siteDir]') - .description('Build website') - .option( - '-sic, --skip-image-compression ', - 'Skip compression of image assets (default: false)' - ) - .action((siteDir = '.', {skipImageCompression}) => { - wrapCommand(build)(path.resolve(siteDir), {skipImageCompression}); - }); - -program - .command('init [projectDir]') - .description('Initialize website') - .action((projectDir = '.') => { - wrapCommand(init)(path.resolve(projectDir)); - }); - -program - .command('start [siteDir]') - .description('Start development server') - .option('-p, --port ', 'use specified port (default: 3000)') - .option('-nw, --no-watch ', 'disable live reload (default: false)') - .action((siteDir = '.', {port, noWatch}) => { - wrapCommand(start)(path.resolve(siteDir), {port, noWatch}); - }); - -program.parse(process.argv); - -if (!process.argv.slice(2).length) { - program.outputHelp(); -} +#!/usr/bin/env node + +const chalk = require('chalk'); +const semver = require('semver'); +const path = require('path'); +const program = require('commander'); +const {build, init, start} = require('../lib'); +const requiredVersion = require('../package.json').engines.node; + +if (!semver.satisfies(process.version, requiredVersion)) { + console.log( + chalk.red(`\nMinimum node version not met :)`) + + chalk.yellow( + `\nYou are using Node ${ + process.version + }, Requirement: Node ${requiredVersion}.\n` + ) + ); + process.exit(1); +} + +function wrapCommand(fn) { + return (...args) => + fn(...args).catch(err => { + console.error(chalk.red(err.stack)); + process.exitCode = 1; + }); +} + +program + .version(require('../package.json').version) + .usage(' [options]'); + +program + .command('build [siteDir]') + .description('Build website') + .option( + '-sic, --skip-image-compression ', + 'Skip compression of image assets (default: false)' + ) + .action((siteDir = '.', {skipImageCompression}) => { + wrapCommand(build)(path.resolve(siteDir), {skipImageCompression}); + }); + +program + .command('init [projectDir]') + .description('Initialize website') + .action((projectDir = '.') => { + wrapCommand(init)(path.resolve(projectDir)); + }); + +program + .command('start [siteDir]') + .description('Start development server') + .option('-p, --port ', 'use specified port (default: 3000)') + .option('-nw, --no-watch ', 'disable live reload (default: false)') + .action((siteDir = '.', {port, noWatch}) => { + wrapCommand(start)(path.resolve(siteDir), {port, noWatch}); + }); + +program.parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp(); +} From cf08a207376c5859eea385c8771e85e0d018336d Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 00:47:14 +0800 Subject: [PATCH 054/135] chore: delete old unused files --- lib/core/blog/index.js | 11 ---- lib/core/docs/index.js | 11 ---- lib/core/index.html | 12 ---- lib/core/markdown/anchors.js | 21 ------- lib/core/markdown/index.js | 115 ----------------------------------- lib/core/markdown/toSlug.js | 66 -------------------- lib/helpers/generate.js | 14 ----- lib/helpers/index.js | 1 - lib/ui/hello.js | 5 -- lib/ui/layout.js | 5 -- 10 files changed, 261 deletions(-) delete mode 100644 lib/core/blog/index.js delete mode 100644 lib/core/docs/index.js delete mode 100644 lib/core/index.html delete mode 100644 lib/core/markdown/anchors.js delete mode 100644 lib/core/markdown/index.js delete mode 100644 lib/core/markdown/toSlug.js delete mode 100644 lib/helpers/generate.js delete mode 100644 lib/helpers/index.js delete mode 100644 lib/ui/hello.js delete mode 100644 lib/ui/layout.js diff --git a/lib/core/blog/index.js b/lib/core/blog/index.js deleted file mode 100644 index f5f1bf7b69..0000000000 --- a/lib/core/blog/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import MarkdownBlock from '../markdown'; - -class Docs extends React.Component { - render() { - const {content, siteConfig} = this.props; - return {content}; - } -} - -module.exports = Docs; diff --git a/lib/core/docs/index.js b/lib/core/docs/index.js deleted file mode 100644 index 1134a6e8d3..0000000000 --- a/lib/core/docs/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import MarkdownBlock from '../markdown'; - -class Blog extends React.Component { - render() { - const {content, siteConfig} = this.props; - return {content}; - } -} - -module.exports = Blog; diff --git a/lib/core/index.html b/lib/core/index.html deleted file mode 100644 index 57c2334380..0000000000 --- a/lib/core/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - -
    - - - \ No newline at end of file diff --git a/lib/core/markdown/anchors.js b/lib/core/markdown/anchors.js deleted file mode 100644 index 2598635e2d..0000000000 --- a/lib/core/markdown/anchors.js +++ /dev/null @@ -1,21 +0,0 @@ -const toSlug = require('./toSlug.js'); - -function anchors(md) { - const originalRender = md.renderer.rules.heading_open; - - md.renderer.rules.heading_open = function(tokens, idx, options, env) { - const textToken = tokens[idx + 1]; - - if (textToken.content) { - const anchor = toSlug(textToken.content, env); - - return ``; - } - - return originalRender(tokens, idx, options, env); - }; -} - -module.exports = anchors; diff --git a/lib/core/markdown/index.js b/lib/core/markdown/index.js deleted file mode 100644 index c50ab500bf..0000000000 --- a/lib/core/markdown/index.js +++ /dev/null @@ -1,115 +0,0 @@ -import React from 'react'; -import Markdown from 'remarkable'; -import hljs from 'highlight.js'; -import prismjs from 'prismjs'; - -import anchors from './anchors.js'; - -class MarkdownBlock extends React.Component { - renderMarkdown(source) { - const alias = { - js: 'jsx' - }; - const {siteConfig} = this.props; - const md = new Markdown({ - langPrefix: 'hljs css language-', - highlight(str, lang) { - lang = - lang || (siteConfig.highlight && siteConfig.highlight.defaultLang); - if (lang === 'text') { - return str; - } - if (lang) { - try { - if ( - siteConfig.usePrism === true || - (siteConfig.usePrism && - siteConfig.usePrism.length > 0 && - siteConfig.usePrism.indexOf(lang) !== -1) - ) { - try { - const language = alias[lang] || lang; - // Currently people using prismjs on Node have to individually require() - // every single language (https://github.com/PrismJS/prism/issues/593) - require(`prismjs/components/prism-${language}.min`); - return prismjs.highlight(str, prismjs.languages[language]); - } catch (err) { - console.error(err); - } - } - if (hljs.getLanguage(lang)) { - return hljs.highlight(lang, str).value; - } - } catch (err) { - console.error(err); - } - } - - try { - return hljs.highlightAuto(str).value; - } catch (err) { - console.error(err); - } - - return ''; - }, - html: true, - linkify: true - }); - - // Register anchors plugin - md.use(anchors); - - // Allow client sites to register their own plugins - if (siteConfig.markdownPlugins) { - siteConfig.markdownPlugins.forEach(plugin => { - md.use(plugin); - }); - } - - const html = md.render(source); - - // Ensure fenced code blocks use Highlight.js hljs class - // https://github.com/jonschlinkert/remarkable/issues/224 - return html.replace(/
    /g, '
    ');
    -  }
    -
    -  content() {
    -    if (this.props.source) {
    -      return (
    -        
    -      );
    -    } else {
    -      return React.Children.map(this.props.children, child => {
    -        if (typeof child === 'string') {
    -          return (
    -            
    -          );
    -        } else {
    -          return child;
    -        }
    -      });
    -    }
    -  }
    -
    -  render() {
    -    const Container = this.props.container;
    -    if (!Container) {
    -      return 
    {this.content()}
    ; - } - return {this.content()}; - } -} - -MarkdownBlock.defaultProps = { - container: 'div', - siteConfig: {} -}; - -export default MarkdownBlock; diff --git a/lib/core/markdown/toSlug.js b/lib/core/markdown/toSlug.js deleted file mode 100644 index aa7ad39df0..0000000000 --- a/lib/core/markdown/toSlug.js +++ /dev/null @@ -1,66 +0,0 @@ -const letters = - '\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'; -const numbers = - '\u0030-\u0039\u00B2\u00B3\u00B9\u00BC-\u00BE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19'; -const exceptAlphanum = new RegExp(`[^${[letters, numbers].join('')}]`, 'g'); - -/** - * Converts a string to a slug, that can be used in heading anchors - * - * @param {string} string - * @param {Object} [context={}] - an optional context to track used slugs and - * ensure that new slug will be unique - * - * @return {string} - */ -module.exports = (string, context = {}) => { - // var accents = "àáäâèéëêìíïîòóöôùúüûñç"; - const accents = - '\u00e0\u00e1\u00e4\u00e2\u00e8' + - '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' + - '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' + - '\u00fa\u00fc\u00fb\u00f1\u00e7'; - - const without = 'aaaaeeeeiiiioooouuuunc'; - - let slug = string - .toString() - // Handle uppercase characters - .toLowerCase() - // Handle accentuated characters - .replace(new RegExp(`[${accents}]`, 'g'), c => - without.charAt(accents.indexOf(c)) - ) - // Replace `.`, `(` and `?` with blank string like Github does - .replace(/\.|\(|\?/g, '') - // Dash special characters - .replace(exceptAlphanum, '-') - // Compress multiple dash - .replace(/-+/g, '-') - // Trim dashes - .replace(/^-|-$/g, ''); - - // Add trailing `-` if string contains ` ...` in the end like Github does - if (/\s[.]{1,}/.test(string)) { - slug += '-'; - } - - if (!context.slugStats) { - context.slugStats = {}; - } - - if (typeof context.slugStats[slug] === 'number') { - // search for an index, that will not clash with an existing headings - while ( - typeof context.slugStats[`${slug}-${++context.slugStats[slug]}`] === - 'number' - ); - slug += `-${context.slugStats[slug]}`; - } - - // we are tracking both original anchors and suffixed to avoid future name - // clashing with headings with numbers e.g. `#Foo 1` may clash with the second `#Foo` - context.slugStats[slug] = 0; - - return slug; -}; diff --git a/lib/helpers/generate.js b/lib/helpers/generate.js deleted file mode 100644 index 6b0550da01..0000000000 --- a/lib/helpers/generate.js +++ /dev/null @@ -1,14 +0,0 @@ -const path = require('path'); -const fs = require('fs-extra'); - -const genPath = path.resolve(__dirname, '../generated'); -fs.ensureDirSync(genPath); - -const genCache = new Map(); -module.exports = async function(file, content) { - const cached = genCache.get(file); - if (cached !== content) { - await fs.writeFile(path.join(genPath, file), content); - genCache.set(file, content); - } -}; diff --git a/lib/helpers/index.js b/lib/helpers/index.js deleted file mode 100644 index 0c43e95b1d..0000000000 --- a/lib/helpers/index.js +++ /dev/null @@ -1 +0,0 @@ -exports.generate = require('./generate'); diff --git a/lib/ui/hello.js b/lib/ui/hello.js deleted file mode 100644 index 1b334b8962..0000000000 --- a/lib/ui/hello.js +++ /dev/null @@ -1,5 +0,0 @@ -const React = require('react'); - -const Hello = props => 'Hello'; - -module.exports = Hello; diff --git a/lib/ui/layout.js b/lib/ui/layout.js deleted file mode 100644 index 580297b680..0000000000 --- a/lib/ui/layout.js +++ /dev/null @@ -1,5 +0,0 @@ -const React = require('react'); - -const Layout = props => 'Layout'; - -module.exports = Layout; From bc7b2835b0ba981c1cf88e97aca392e4b933350f Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 01:33:25 +0800 Subject: [PATCH 055/135] feat: prototype custom pages site generation --- lib/core/App.js | 5 +++-- lib/load/index.js | 13 ++++++++++++- lib/load/pages.js | 23 +++++++++++++++++++++++ lib/load/routes.js | 21 ++++++++++++++++++--- lib/load/utils.js | 2 +- lib/webpack/base.js | 1 + lib/webpack/prod.js | 4 ++-- website/pages/index.js | 18 ++++++++++++++++++ 8 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 lib/load/pages.js create mode 100644 website/pages/index.js diff --git a/lib/core/App.js b/lib/core/App.js index 994f141f82..6cef21dbbe 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -1,6 +1,7 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line -import props from '@generated/docsData'; // eslint-disable-line +import docsData from '@generated/docsData'; // eslint-disable-line +import pagesData from '@generated/pagesData'; // eslint-disable-line -export default () => renderRoutes(routes, props); +export default () => renderRoutes(routes, {docsData, pagesData}); diff --git a/lib/load/index.js b/lib/load/index.js index c1729f2251..7ce9b4540a 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -2,6 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); const loadDocs = require('./docs'); +const loadPages = require('./pages'); const {generate} = require('./utils'); const genRoutesConfig = require('./routes'); @@ -18,7 +19,15 @@ module.exports = async function load(siteDir) { const docsData = await loadDocs(docsDir); await generate( 'docsData.js', - `export const docsData = ${JSON.stringify(docsData, null, 2)}` + `export default ${JSON.stringify(docsData, null, 2)};` + ); + + // pages + const pagesDir = path.resolve(siteDir, 'pages'); + const pagesData = await loadPages(pagesDir); + await generate( + 'pagesData.js', + `export default ${JSON.stringify(pagesData, null, 2)};` ); // resolve outDir @@ -38,6 +47,8 @@ module.exports = async function load(siteDir) { siteDir, docsDir, docsData, + pagesDir, + pagesData, outDir, themePath, baseUrl diff --git a/lib/load/pages.js b/lib/load/pages.js new file mode 100644 index 0000000000..c3023b81ca --- /dev/null +++ b/lib/load/pages.js @@ -0,0 +1,23 @@ +const fs = require('fs-extra'); +const path = require('path'); +const globby = require('globby'); +const {encodePath, fileToPath} = require('./utils'); + +async function loadPages(pagesDir) { + const pagesFiles = await globby(['**/*.js'], { + cwd: pagesDir + }); + + const pagesData = await Promise.all( + pagesFiles.map(async source => { + const filepath = path.resolve(pagesDir, source); + return { + path: encodePath(fileToPath(source)), + source + }; + }) + ); + return pagesData; +} + +module.exports = loadPages; diff --git a/lib/load/routes.js b/lib/load/routes.js index 1482b66ba9..cdfd203e01 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,7 +1,7 @@ const path = require('path'); const {fileToComponentName} = require('./utils'); -async function genRoutesConfig({docsData, docsDir}) { +async function genRoutesConfig({docsData, docsDir, pagesDir, pagesData}) { function genDocsRoute({path: docsPath, source}) { const componentName = fileToComponentName(source); return ` @@ -17,6 +17,20 @@ async function genRoutesConfig({docsData, docsDir}) { return `import ${componentName} from ${JSON.stringify(filePath)}`; } + function genPagesRoute({path: pagesPath, source}) { + const componentName = fileToComponentName(source); + return ` + { + path: ${JSON.stringify(pagesPath)}, + component: ${componentName} + }`; + } + + function genPagesImport({source}) { + const componentName = fileToComponentName(source); + return `import ${componentName} from '@pages/${source}'`; + } + const notFoundRoute = `, { path: '*', @@ -27,9 +41,10 @@ async function genRoutesConfig({docsData, docsDir}) { `import React from 'react';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + + `${pagesData.map(genPagesImport).join('\n')}\n` + `${docsData.map(genDocsImport).join('\n')}\n` + - `const routes = [${docsData - .map(genDocsRoute) + `const routes = [${docsData.map(genDocsRoute).join(',')},${pagesData + .map(genPagesRoute) .join(',')}${notFoundRoute}\n];\n` + `export default routes;\n` ); diff --git a/lib/load/utils.js b/lib/load/utils.js index 1163c886bf..052f7b24b6 100644 --- a/lib/load/utils.js +++ b/lib/load/utils.js @@ -13,7 +13,7 @@ async function generate(file, content) { } } -const indexRE = /(^|.*\/)index\.md$/i; +const indexRE = /(^|.*\/)index\.(md|js)$/i; const mdRE = /\.md$/; function fileToPath(file) { diff --git a/lib/webpack/base.js b/lib/webpack/base.js index d577671721..711cb0ea44 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -19,6 +19,7 @@ module.exports = function createBaseConfig(props) { .set('symlinks', true) .alias.set('@theme', themePath) .set('@site', siteDir) + .set('@pages', path.resolve(siteDir, 'pages')) .set('@generated', path.resolve(__dirname, '../core/generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index 0bca7e7345..d284f706d1 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -11,10 +11,10 @@ module.exports = function createProdConfig(props) { // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) config.output.globalObject('this'); - const {siteConfig, docsData} = props; + const {siteConfig, docsData, pagesData} = props; // Find all available paths - const paths = docsData.map(docs => docs.path); + const paths = [...docsData, ...pagesData].map(data => data.path); config.plugin('StaticSiteGenerator').use(staticSiteGeneratorPlugin, [ { diff --git a/website/pages/index.js b/website/pages/index.js new file mode 100644 index 0000000000..19f3a8d681 --- /dev/null +++ b/website/pages/index.js @@ -0,0 +1,18 @@ +import React from 'react'; +import {Link} from 'react-router-dom'; + +export default class Home extends React.Component { + render() { + const {pagesData, docsData} = this.props; + const routeLinks = [...pagesData, ...docsData].map(data => ( +
  • + {data.path} +
  • + )); + return ( +
    +
      Available Routes{routeLinks}
    +
    + ); + } +} From 33105ba3cc23b9d5d061ec3c6706014404e41770 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 01:43:52 +0800 Subject: [PATCH 056/135] chore: add README --- README.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e68887c70b..48ee655ac5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,34 @@ # Munseo -📝⚡️ Transform your document (문서) to a website \ No newline at end of file +📝⚡️ Transform your document (문서) to a website + +# Disclaimer: +This is still a *WORK IN PROGRESS* (prototype static site generator). Expect lot of bugs :) + +# Introduction +- Each page generated is own pre-rendered static HTML. +- Once the page is loaded, ReactDOM takes over the static content and turns it into a full Single-Page Application (SPA). + +# Current +- Generate page for `.md` files on `docs` +- Generate page for `.js` React files on `website/pages` + +# Quick Start + +Install with `yarn`. Check all available commands with: + +``` +yarn munseo --help +``` + +## Development Server + +```bash +yarn start # open http://localhost:3000/ +``` + +## Production Build + +```bash +yarn build # check website/build +``` + From 77ec02a27802a7263d3c88fab08bc416f520c8ba Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 02:27:44 +0800 Subject: [PATCH 057/135] chore: eslint fix --- lib/load/pages.js | 13 ++++--------- lib/load/routes.js | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/load/pages.js b/lib/load/pages.js index c3023b81ca..7278754164 100644 --- a/lib/load/pages.js +++ b/lib/load/pages.js @@ -1,5 +1,3 @@ -const fs = require('fs-extra'); -const path = require('path'); const globby = require('globby'); const {encodePath, fileToPath} = require('./utils'); @@ -9,13 +7,10 @@ async function loadPages(pagesDir) { }); const pagesData = await Promise.all( - pagesFiles.map(async source => { - const filepath = path.resolve(pagesDir, source); - return { - path: encodePath(fileToPath(source)), - source - }; - }) + pagesFiles.map(async source => ({ + path: encodePath(fileToPath(source)), + source + })) ); return pagesData; } diff --git a/lib/load/routes.js b/lib/load/routes.js index cdfd203e01..f4ca448c05 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,7 +1,7 @@ const path = require('path'); const {fileToComponentName} = require('./utils'); -async function genRoutesConfig({docsData, docsDir, pagesDir, pagesData}) { +async function genRoutesConfig({docsData, docsDir, pagesData}) { function genDocsRoute({path: docsPath, source}) { const componentName = fileToComponentName(source); return ` From fa02f6ef606e1b165b6558cfdaaf024115fd859c Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 02:28:29 +0800 Subject: [PATCH 058/135] feat: copy static files for production build --- docs/hello.md | 4 +++- lib/commands/build.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/hello.md b/docs/hello.md index 71fcb798ad..f07b1a8fc8 100644 --- a/docs/hello.md +++ b/docs/hello.md @@ -3,4 +3,6 @@ id: hello title: Hello, World ! --- -Hi, Endilie here :) \ No newline at end of file +Hi, Endilie here :) + +![sakura](/img/sakura.png) \ No newline at end of file diff --git a/lib/commands/build.js b/lib/commands/build.js index abc9be7068..62d8f226d4 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -2,6 +2,8 @@ const webpackNiceLog = require('webpack-nicelog'); const webpack = require('webpack'); const path = require('path'); const chalk = require('chalk'); +const fs = require('fs-extra'); +const globby = require('globby'); const load = require('../load'); const createProdConfig = require('../webpack/prod'); @@ -51,6 +53,20 @@ module.exports = async function build(siteDir, cliOptions = {}) { await compile(config); const {outDir} = props; + + // copy static files + const staticDir = path.resolve(siteDir, 'static'); + const staticFiles = await globby(['**'], { + cwd: staticDir + }); + await Promise.all( + staticFiles.map(async source => { + const fromPath = path.resolve(staticDir, source); + const toPath = path.resolve(outDir, source); + return fs.copy(fromPath, toPath); + }) + ); + const relativeDir = path.relative(process.cwd(), outDir); console.log( `\n${chalk.green('Success!')} Generated static files in ${chalk.cyan( From 2996e011f820f34e158d76fe111ef0cc77405521 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 14:11:31 +0800 Subject: [PATCH 059/135] chore: update readme & dependencies --- README.md | 19 ++----------------- package.json | 6 +++--- yarn.lock | 6 +++--- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 48ee655ac5..c34e1df0a0 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,10 @@ 📝⚡️ Transform your document (문서) to a website # Disclaimer: -This is still a *WORK IN PROGRESS* (prototype static site generator). Expect lot of bugs :) - -# Introduction -- Each page generated is own pre-rendered static HTML. -- Once the page is loaded, ReactDOM takes over the static content and turns it into a full Single-Page Application (SPA). - -# Current -- Generate page for `.md` files on `docs` -- Generate page for `.js` React files on `website/pages` +This is still a *WORK IN PROGRESS*. Expect lot of bugs :) # Quick Start -Install with `yarn`. Check all available commands with: - -``` -yarn munseo --help -``` - ## Development Server ```bash @@ -30,5 +16,4 @@ yarn start # open http://localhost:3000/ ```bash yarn build # check website/build -``` - +``` \ No newline at end of file diff --git a/package.json b/package.json index cb69e0c103..1137b509b4 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ }, "scripts": { "munseo": "node bin/munseo", - "start": "yarn munseo start website", - "build": "yarn munseo build website", + "start": "node bin/munseo start website", + "build": "node bin/munseo build website", "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "test": "jest" @@ -69,7 +69,7 @@ "static-site-generator-webpack-plugin": "^3.4.1", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", - "webpack-nicelog": "^2.0.0", + "webpack-nicelog": "^2.1.0", "webpack-serve": "^2.0.2" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 2252a088cf..16a0255278 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6799,9 +6799,9 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: loglevelnext "^1.0.1" uuid "^3.1.0" -webpack-nicelog@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.0.0.tgz#7e4d68c54e7bd82adf19fde1eb3d43e767eea887" +webpack-nicelog@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.1.0.tgz#fb8d89ec1976d36122e8d407bf318eb38c094155" dependencies: chalk "^2.4.1" react-dev-utils "^5.0.1" From a9c3d50a68955379c05c82abd8122b082899a0d5 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 14:24:09 +0800 Subject: [PATCH 060/135] chore: more test files --- docs/foo/bar.md | 62 +++++++++++++++++++++- docs/foo/baz.md | 73 +++++++++++++++++++++++++- docs/hello.md | 34 +++++++++++- website/static/img/minion.png | Bin 0 -> 93508 bytes website/static/img/sakura.png | Bin 79340 -> 0 bytes website/static/img/stormtroopocat.jpg | Bin 0 -> 95977 bytes 6 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 website/static/img/minion.png delete mode 100644 website/static/img/sakura.png create mode 100644 website/static/img/stormtroopocat.jpg diff --git a/docs/foo/bar.md b/docs/foo/bar.md index 4e98647e03..9f978009c5 100644 --- a/docs/foo/bar.md +++ b/docs/foo/bar.md @@ -3,4 +3,64 @@ id: bar title: Bar --- -Lorem ipsumsdsdsad +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/docs/foo/baz.md b/docs/foo/baz.md index 2be434ffdc..add729c51d 100644 --- a/docs/foo/baz.md +++ b/docs/foo/baz.md @@ -3,4 +3,75 @@ id: baz title: baz --- -Life is so good +## Images + +![Minion](/img/minion.png) +![Stormtroopocat](/img/stormtroopocat.jpg) + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/docs/hello.md b/docs/hello.md index f07b1a8fc8..a392b2ca54 100644 --- a/docs/hello.md +++ b/docs/hello.md @@ -5,4 +5,36 @@ title: Hello, World ! Hi, Endilie here :) -![sakura](/img/sakura.png) \ No newline at end of file +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/website/static/img/minion.png b/website/static/img/minion.png new file mode 100644 index 0000000000000000000000000000000000000000..4c5684cee2c18339b48fa7818e6a23b9bdc39c5c GIT binary patch literal 93508 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

    Vor@gg$bT8y# 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 literal 0 HcmV?d00001 diff --git a/website/static/img/sakura.png b/website/static/img/sakura.png deleted file mode 100644 index e10909398bc26a8dc747cbea0dd6479ed5a84aa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79340 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 DKbw08 diff --git a/website/static/img/stormtroopocat.jpg b/website/static/img/stormtroopocat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3400da70ea2a7e14bf88dc4c17a86ba9a1f17944 GIT binary patch literal 95977 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 literal 0 HcmV?d00001 From 44122cd202e00abcb1af28c3ede0ebef1d9d10e6 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 14:25:02 +0800 Subject: [PATCH 061/135] refactor: code --- lib/commands/build.js | 18 +++--------------- lib/commands/start.js | 40 +++++++++------------------------------- lib/webpack/dev.js | 18 ++++++++++++++++++ lib/webpack/prod.js | 9 +++++++-- 4 files changed, 37 insertions(+), 48 deletions(-) diff --git a/lib/commands/build.js b/lib/commands/build.js index 62d8f226d4..7f017ca84e 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -1,4 +1,3 @@ -const webpackNiceLog = require('webpack-nicelog'); const webpack = require('webpack'); const path = require('path'); const chalk = require('chalk'); @@ -11,14 +10,13 @@ function compile(config) { return new Promise((resolve, reject) => { webpack(config, (err, stats) => { if (err) { - return reject(err); + reject(err); } if (stats.hasErrors()) { stats.toJson().errors.forEach(e => { console.error(e); }); reject(new Error(`Failed to compile with errors.`)); - return false; } if (stats.hasWarnings()) { stats.toJson().warnings.forEach(warning => { @@ -26,7 +24,6 @@ function compile(config) { }); } resolve(stats.toJson({modules: false})); - return true; }); }); } @@ -38,23 +35,14 @@ module.exports = async function build(siteDir, cliOptions = {}) { const props = await load(siteDir); - // resolve webpack config - let config = createProdConfig(props); - config.plugin('WebpackNiceLog').use(webpackNiceLog, [ - { - name: 'Production' - } - ]); - // create compiler from generated webpack config - config = config.toConfig(); + const config = createProdConfig(props).toConfig(); // compile! await compile(config); - const {outDir} = props; - // copy static files + const {outDir} = props; const staticDir = path.resolve(siteDir, 'static'); const staticFiles = await globby(['**'], { cwd: staticDir diff --git a/lib/commands/start.js b/lib/commands/start.js index a150ad276d..cc373b79b4 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -10,8 +10,6 @@ const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); -const webpackNiceLog = require('webpack-nicelog'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../load'); const createDevConfig = require('../webpack/dev'); @@ -25,6 +23,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { // Process all related files as a prop const props = await load(siteDir); + // Reload files processing if (!cliOptions.noWatch) { const reload = () => { load(siteDir).catch(err => { @@ -49,43 +48,17 @@ module.exports = async function start(siteDir, cliOptions = {}) { const port = await getPort(cliOptions.port); const {baseUrl} = props; - // resolve webpack config - let config = createDevConfig(props); - config.plugin('WebpackNiceLog').use(webpackNiceLog, [ - { - name: 'Munseo', - onDone: () => { - console.log( - `\n${chalk.blue('Development server available at ')}${chalk.cyan( - `http://localhost:${port}${baseUrl}` - )}` - ); - } - } - ]); - config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ - { - inject: false, - hash: true, - template: path.resolve(__dirname, '../core/devTemplate.ejs'), - filename: 'index.html', - title: props.siteConfig.title - } - ]); - // create compiler from generated webpack config - config = config.toConfig(); + const config = createDevConfig(props).toConfig(); const compiler = webpack(config); // webpack-serve - const nonExistentDir = path.resolve(__dirname, 'non-existent'); setTimeout(async () => { await serve( {}, { - content: [nonExistentDir], compiler, - open: false, + open: true, devMiddleware: { logLevel: 'silent' }, @@ -96,11 +69,16 @@ module.exports = async function start(siteDir, cliOptions = {}) { logLevel: 'error', port, add: app => { + // serve static files const staticDir = path.resolve(siteDir, 'static'); if (fs.existsSync(staticDir)) { app.use(mount(baseUrl, serveStatic(staticDir))); } - app.use(range); // enable range request https://tools.ietf.org/html/rfc7233 + + // enable HTTP range requests + app.use(range); + + // rewrite request to `/` since this is a SPA app.use( convert( history({ diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js index 97e42404b0..0956603f76 100644 --- a/lib/webpack/dev.js +++ b/lib/webpack/dev.js @@ -1,4 +1,6 @@ const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); module.exports = function createDevConfig(props) { @@ -6,5 +8,21 @@ module.exports = function createDevConfig(props) { config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); + const {siteConfig} = props; + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + inject: false, + hash: true, + template: path.resolve(__dirname, '../core/devTemplate.ejs'), + filename: 'index.html', + title: siteConfig.title + } + ]); + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ + { + name: 'Development' + } + ]); + return config; }; diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index d284f706d1..ee22a138bf 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -1,5 +1,6 @@ const path = require('path'); const staticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin'); +const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); module.exports = function createProdConfig(props) { @@ -13,9 +14,8 @@ module.exports = function createProdConfig(props) { const {siteConfig, docsData, pagesData} = props; - // Find all available paths + // Find all available paths to be rendered const paths = [...docsData, ...pagesData].map(data => data.path); - config.plugin('StaticSiteGenerator').use(staticSiteGeneratorPlugin, [ { entry: 'main', @@ -27,6 +27,11 @@ module.exports = function createProdConfig(props) { paths } ]); + config.plugin('WebpackNiceLog').use(webpackNiceLog, [ + { + name: 'Production' + } + ]); return config; }; From 0fcad83410caf5cb3536c94cab5ce92823165313 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 14:26:12 +0800 Subject: [PATCH 062/135] chore: add blog test file --- ...018-08-05-sakura.md => 2018-08-08-sakura.md} | 0 website/static/img/sakura.png | Bin 0 -> 79340 bytes 2 files changed, 0 insertions(+), 0 deletions(-) rename website/blog/{2018-08-05-sakura.md => 2018-08-08-sakura.md} (100%) create mode 100644 website/static/img/sakura.png diff --git a/website/blog/2018-08-05-sakura.md b/website/blog/2018-08-08-sakura.md similarity index 100% rename from website/blog/2018-08-05-sakura.md rename to website/blog/2018-08-08-sakura.md diff --git a/website/static/img/sakura.png b/website/static/img/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 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 DKbw08 literal 0 HcmV?d00001 From d9def2865a79465d7ac3716ec883b58a72d9342b Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 14:45:54 +0800 Subject: [PATCH 063/135] fix: use exact path & handle non-index pages --- lib/load/routes.js | 2 ++ lib/load/utils.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/load/routes.js b/lib/load/routes.js index f4ca448c05..fdc8af9b06 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -7,6 +7,7 @@ async function genRoutesConfig({docsData, docsDir, pagesData}) { return ` { path: ${JSON.stringify(docsPath)}, + exact: true, component: () => <${componentName} /> }`; } @@ -22,6 +23,7 @@ async function genRoutesConfig({docsData, docsDir, pagesData}) { return ` { path: ${JSON.stringify(pagesPath)}, + exact: true, component: ${componentName} }`; } diff --git a/lib/load/utils.js b/lib/load/utils.js index 052f7b24b6..2080afbefa 100644 --- a/lib/load/utils.js +++ b/lib/load/utils.js @@ -14,13 +14,13 @@ async function generate(file, content) { } const indexRE = /(^|.*\/)index\.(md|js)$/i; -const mdRE = /\.md$/; +const extRE = /\.(md|js)$/; function fileToPath(file) { if (indexRE.test(file)) { return file.replace(indexRE, '/$1'); } - return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`; + return `/${file.replace(extRE, '').replace(/\\/g, '/')}`; } function encodePath(userpath) { From 1eef464fc0b9dd755b27335e7b7bb20bfb4fd4b4 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 15:02:13 +0800 Subject: [PATCH 064/135] chore: add pages/tictactoe.js to test reactDOM --- website/pages/index.js | 6 +- website/pages/tictactoe.js | 165 +++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 website/pages/tictactoe.js diff --git a/website/pages/index.js b/website/pages/index.js index 19f3a8d681..2d89400073 100644 --- a/website/pages/index.js +++ b/website/pages/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import TicTacToe from './tictactoe'; import {Link} from 'react-router-dom'; export default class Home extends React.Component { @@ -11,7 +12,10 @@ export default class Home extends React.Component { )); return (

    -
      Available Routes{routeLinks}
    +

    Available Urls

    +
      {routeLinks}
    +

    Play some TicTacToe

    +
    ); } diff --git a/website/pages/tictactoe.js b/website/pages/tictactoe.js new file mode 100644 index 0000000000..b5af6ad4e0 --- /dev/null +++ b/website/pages/tictactoe.js @@ -0,0 +1,165 @@ +import React from 'react'; + +const square = { + background: '#fff', + border: '1px solid #999', + float: 'left', + fontSize: '24px', + fontWeight: 'bold', + lineHeight: '34px', + height: '34px', + marginright: '-1px', + marginTop: '-1px', + padding: '0', + textAlign: 'center', + width: '34px' +}; + +const boardRow = { + clear: 'both', + content: '', + display: 'table' +}; + +const game = { + display: 'flex', + flexDirection: 'row' +}; + +function Square(props) { + return ( + + ); +} + +function calculateWinner(squares) { + const lines = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6] + ]; + for (let i = 0; i < lines.length; i++) { + const [a, b, c] = lines[i]; + if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { + return squares[a]; + } + } + return null; +} + +class Board extends React.Component { + renderSquare(i) { + return ( + this.props.onClick(i)} + /> + ); + } + + render() { + return ( +
    +
    + {this.renderSquare(0)} + {this.renderSquare(1)} + {this.renderSquare(2)} +
    +
    + {this.renderSquare(3)} + {this.renderSquare(4)} + {this.renderSquare(5)} +
    +
    + {this.renderSquare(6)} + {this.renderSquare(7)} + {this.renderSquare(8)} +
    +
    + ); + } +} + +class Game extends React.Component { + constructor(props) { + super(props); + this.state = { + history: [ + { + squares: Array(9).fill(null) + } + ], + stepNumber: 0, + xIsNext: true + }; + } + + handleClick(i) { + const history = this.state.history.slice(0, this.state.stepNumber + 1); + const current = history[history.length - 1]; + const squares = current.squares.slice(); + if (calculateWinner(squares) || squares[i]) { + return; + } + squares[i] = this.state.xIsNext ? 'X' : 'O'; + this.setState({ + history: history.concat([ + { + squares: squares + } + ]), + stepNumber: history.length, + xIsNext: !this.state.xIsNext + }); + } + + jumpTo(step) { + this.setState({ + stepNumber: step, + xIsNext: step % 2 === 0 + }); + } + + render() { + const history = this.state.history; + const current = history[this.state.stepNumber]; + const winner = calculateWinner(current.squares); + + const moves = history.map((step, move) => { + const desc = move ? 'Go to move #' + move : 'Go to game start'; + return ( +
  • + +
  • + ); + }); + + let status; + if (winner) { + status = 'Winner: ' + winner; + } else { + status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); + } + + return ( +
    +
    + this.handleClick(i)} /> +
    +
    +
    {status}
    +
      {moves}
    +
    +
    + ); + } +} + +export default Game; From 05c90a208cc698a037410d821e631ae70744cb7e Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 17:19:26 +0800 Subject: [PATCH 065/135] chore: minimal es6 refactor --- lib/core/components/Markdown/anchors.js | 2 +- lib/core/components/Markdown/index.js | 11 +++++------ lib/webpack/base.js | 4 ++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/core/components/Markdown/anchors.js b/lib/core/components/Markdown/anchors.js index e62424b081..ab0eb2a2bc 100644 --- a/lib/core/components/Markdown/anchors.js +++ b/lib/core/components/Markdown/anchors.js @@ -1,4 +1,4 @@ -const toSlug = require('./toSlug.js'); +import toSlug from './toSlug.js'; function anchors(md) { const originalRender = md.renderer.rules.heading_open; diff --git a/lib/core/components/Markdown/index.js b/lib/core/components/Markdown/index.js index 8617c6bd93..e2ca07cffb 100644 --- a/lib/core/components/Markdown/index.js +++ b/lib/core/components/Markdown/index.js @@ -1,11 +1,10 @@ /* eslint-disable react/no-danger */ -const React = require('react'); -const Markdown = require('remarkable'); -const hljs = require('highlight.js'); -const prismjs = require('prismjs'); - -const anchors = require('./anchors.js'); +import React from 'react'; +import Markdown from 'remarkable'; +import hljs from 'highlight.js'; +import prismjs from 'prismjs'; +import anchors from './anchors'; class MarkdownBlock extends React.Component { content() { diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 711cb0ea44..e537417a4f 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -15,6 +15,10 @@ module.exports = function createBaseConfig(props) { .filename(isProd ? 'bundle.js' : '[name].js') .publicPath(isProd ? baseUrl : '/'); + if (!isProd) { + config.devtool('cheap-module-eval-source-map'); + } + config.resolve .set('symlinks', true) .alias.set('@theme', themePath) From 8538a10a669ceb5c95065450df9221810b4435ec Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 19:58:42 +0800 Subject: [PATCH 066/135] dep: update webpack-nicelog --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1137b509b4..fbbd28bc89 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "static-site-generator-webpack-plugin": "^3.4.1", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", - "webpack-nicelog": "^2.1.0", + "webpack-nicelog": "^2.2.1", "webpack-serve": "^2.0.2" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 16a0255278..721cde8b02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6799,9 +6799,9 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: loglevelnext "^1.0.1" uuid "^3.1.0" -webpack-nicelog@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.1.0.tgz#fb8d89ec1976d36122e8d407bf318eb38c094155" +webpack-nicelog@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.2.1.tgz#e3458003ce0d98966e930657176fb4eb6f536b85" dependencies: chalk "^2.4.1" react-dev-utils "^5.0.1" From d36c17f368ff940b1d7035a82b15d5cdaa353de7 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 20:47:35 +0800 Subject: [PATCH 067/135] refactor: use alias for docs & eslint --- lib/core/components/Markdown/anchors.js | 2 +- lib/load/routes.js | 14 ++++++++------ lib/webpack/base.js | 13 +++++++++++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/core/components/Markdown/anchors.js b/lib/core/components/Markdown/anchors.js index ab0eb2a2bc..394864b331 100644 --- a/lib/core/components/Markdown/anchors.js +++ b/lib/core/components/Markdown/anchors.js @@ -1,4 +1,4 @@ -import toSlug from './toSlug.js'; +import toSlug from './toSlug'; function anchors(md) { const originalRender = md.renderer.rules.heading_open; diff --git a/lib/load/routes.js b/lib/load/routes.js index fdc8af9b06..908baa2d73 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,21 +1,23 @@ -const path = require('path'); const {fileToComponentName} = require('./utils'); -async function genRoutesConfig({docsData, docsDir, pagesData}) { +async function genRoutesConfig({docsData, pagesData}) { function genDocsRoute({path: docsPath, source}) { const componentName = fileToComponentName(source); return ` { path: ${JSON.stringify(docsPath)}, exact: true, - component: () => <${componentName} /> + component: () => ( + + <${componentName} /> + + ) }`; } function genDocsImport({source}) { - const filePath = path.resolve(docsDir, source); const componentName = fileToComponentName(source); - return `import ${componentName} from ${JSON.stringify(filePath)}`; + return `import ${componentName} from '@docs/${source}';`; } function genPagesRoute({path: pagesPath, source}) { @@ -30,7 +32,7 @@ async function genRoutesConfig({docsData, docsDir, pagesData}) { function genPagesImport({source}) { const componentName = fileToComponentName(source); - return `import ${componentName} from '@pages/${source}'`; + return `import ${componentName} from '@pages/${source}';`; } const notFoundRoute = `, diff --git a/lib/webpack/base.js b/lib/webpack/base.js index e537417a4f..97e99c2746 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -4,7 +4,15 @@ const path = require('path'); const mdLoader = require.resolve('./loader/markdown'); module.exports = function createBaseConfig(props) { - const {siteConfig, outDir, themePath, siteDir, baseUrl} = props; + const { + siteConfig, + outDir, + themePath, + docsDir, + pagesDir, + siteDir, + baseUrl + } = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -23,7 +31,8 @@ module.exports = function createBaseConfig(props) { .set('symlinks', true) .alias.set('@theme', themePath) .set('@site', siteDir) - .set('@pages', path.resolve(siteDir, 'pages')) + .set('@docs', docsDir) + .set('@pages', pagesDir) .set('@generated', path.resolve(__dirname, '../core/generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); From 687bf09c9644bbc9b492da9350a12c4e718ec516 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 8 Aug 2018 21:24:33 +0800 Subject: [PATCH 068/135] dep: add bundle analyzer temporarily to check bundle size --- lib/webpack/loader/markdown.js | 1 - lib/webpack/prod.js | 17 +- package.json | 1 + yarn.lock | 274 +++++++++++++++++++++++++++++++-- 4 files changed, 270 insertions(+), 23 deletions(-) diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index 7cf53f1ccc..d4a14e6310 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -1,6 +1,5 @@ const {getOptions} = require('loader-utils'); const fm = require('front-matter'); -// const MarkdownBlock = require('../../core/components/markdown'); module.exports = function(fileString) { const options = getOptions(this); diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index ee22a138bf..2dcb8e91a6 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -1,6 +1,7 @@ const path = require('path'); -const staticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin'); +const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); +const bundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const createBaseConfig = require('./base'); module.exports = function createProdConfig(props) { @@ -16,7 +17,7 @@ module.exports = function createProdConfig(props) { // Find all available paths to be rendered const paths = [...docsData, ...pagesData].map(data => data.path); - config.plugin('StaticSiteGenerator').use(staticSiteGeneratorPlugin, [ + config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', locals: { @@ -27,11 +28,11 @@ module.exports = function createProdConfig(props) { paths } ]); - config.plugin('WebpackNiceLog').use(webpackNiceLog, [ - { - name: 'Production' - } - ]); - + // show compilation progress bar and build time + config.plugin('niceLog').use(webpackNiceLog, [{name: 'Production'}]); + + // Webpack Bundle Analyzer to check which causes huge bundle size + config.plugin('bundleAnalyzer').use(bundleAnalyzer); + return config; }; diff --git a/package.json b/package.json index fbbd28bc89..ab056b14b9 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "semver": "^5.5.0", "static-site-generator-webpack-plugin": "^3.4.1", "webpack": "^4.16.3", + "webpack-bundle-analyzer": "^2.13.1", "webpack-chain": "^4.8.0", "webpack-nicelog": "^2.2.1", "webpack-serve": "^2.0.2" diff --git a/yarn.lock b/yarn.lock index 721cde8b02..81576d1c68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -234,7 +234,7 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -accepts@^1.3.5: +accepts@^1.3.5, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: @@ -263,7 +263,7 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.0.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: +acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -423,6 +423,10 @@ array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + array-includes@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" @@ -1133,6 +1137,14 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bfj-node4@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.3.1.tgz#e23d8b27057f1d0214fc561142ad9db998f26830" + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + tryer "^1.0.0" + big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -1149,6 +1161,21 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -1299,6 +1326,10 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + cacache@^10.0.4: version "10.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" @@ -1430,6 +1461,10 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +check-types@^7.3.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" + cheerio@^0.22.0: version "0.22.0" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" @@ -1590,6 +1625,10 @@ commander@2.16.x, commander@^2.11.0, commander@^2.16.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" +commander@^2.13.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1661,11 +1700,11 @@ contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -content-disposition@~0.5.2: +content-disposition@0.5.2, content-disposition@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type@^1.0.4: +content-type@^1.0.4, content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -1673,6 +1712,14 @@ convert-source-map@^1.4.0, convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + cookies@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" @@ -1838,7 +1885,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1943,6 +1990,10 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + depd@^1.1.2, depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -1954,7 +2005,7 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@^1.0.4: +destroy@^1.0.4, destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2107,6 +2158,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +ejs@^2.5.7: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" @@ -2131,6 +2186,10 @@ emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -2212,7 +2271,7 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.1: d "1" es5-ext "~0.10.14" -escape-html@^1.0.3: +escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2404,6 +2463,10 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + eval@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.2.tgz#9f7103284c105a66df4030b2b3273165837013da" @@ -2502,6 +2565,41 @@ expect@^23.4.0: jest-message-util "^23.4.0" jest-regex-util "^23.3.0" +express@^4.16.2: + version "4.16.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.3" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -2633,6 +2731,10 @@ filesize@3.5.11: version "3.5.11" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.11.tgz#1919326749433bb3cf77368bd158caabcc19e9ee" +filesize@^3.5.11: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -2652,6 +2754,18 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + find-cache-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" @@ -2715,13 +2829,17 @@ form-data@~2.3.1: combined-stream "1.0.6" mime-types "^2.1.12" +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: map-cache "^0.2.2" -fresh@~0.5.2: +fresh@0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -2945,6 +3063,13 @@ gzip-size@3.0.0: dependencies: duplexer "^0.1.1" +gzip-size@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-4.1.0.tgz#8ae096257eabe7d69c45be2b67c448124ffb517c" + dependencies: + duplexer "^0.1.1" + pify "^3.0.0" + handlebars@^4.0.3: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" @@ -3139,6 +3264,15 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.6.1" +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + http-errors@^1.6.1, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -3263,6 +3397,10 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4452,6 +4590,10 @@ meow@^5.0.0: trim-newlines "^2.0.0" yargs-parser "^10.0.0" +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + merge-options@^1.0.0, merge-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32" @@ -4472,6 +4614,10 @@ merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -4525,6 +4671,10 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.17, mime-types@~2.1.18: dependencies: mime-db "~1.35.0" +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + mime@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" @@ -4907,7 +5057,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -on-finished@^2.3.0: +on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: @@ -4929,6 +5079,10 @@ only@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" +opener@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + opn@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" @@ -5098,7 +5252,7 @@ parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" -parseurl@^1.3.2: +parseurl@^1.3.2, parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -5140,6 +5294,10 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" @@ -5310,6 +5468,13 @@ prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" +proxy-addr@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -5359,6 +5524,10 @@ punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" +qs@6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + qs@~6.5.1: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -5400,10 +5569,19 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.0.3: +range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -5850,6 +6028,10 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5904,10 +6086,37 @@ semver-diff@^2.0.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + serialize-javascript@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -5938,6 +6147,10 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -6151,10 +6364,14 @@ static-site-generator-webpack-plugin@^3.4.1: url "^0.11.0" webpack-sources "^0.2.0" -"statuses@>= 1.4.0 < 2", statuses@^1.5.0: +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", statuses@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + std-env@^1.1.0, std-env@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/std-env/-/std-env-1.3.1.tgz#4e1758412439e9ece1d437b1b098551911aa44ee" @@ -6457,6 +6674,10 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +tryer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -6481,7 +6702,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@^1.6.16: +type-is@^1.6.16, type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: @@ -6575,6 +6796,10 @@ universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -6678,6 +6903,10 @@ utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + uuid@^3.1.0: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -6697,7 +6926,7 @@ value-equal@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" -vary@^1.1.2: +vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -6758,6 +6987,23 @@ webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" +webpack-bundle-analyzer@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz#07d2176c6e86c3cdce4c23e56fae2a7b6b4ad526" + dependencies: + acorn "^5.3.0" + bfj-node4 "^5.2.0" + chalk "^2.3.0" + commander "^2.13.0" + ejs "^2.5.7" + express "^4.16.2" + filesize "^3.5.11" + gzip-size "^4.1.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + opener "^1.4.3" + ws "^4.0.0" + webpack-chain@^4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.8.0.tgz#06fc3dbb9f2707d4c9e899fc6250fbcf2afe6fd1" From bf94bf96f8d220670cbba1796fb29114dfac2dd3 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 10 Aug 2018 14:52:02 +0800 Subject: [PATCH 069/135] test: add test for load config --- lib/load/config.js | 12 +++++++ package.json | 9 +---- test/jest.config.js | 12 +++++++ test/load/__fixtures__/bad-site/siteConfig.js | 4 +++ .../__fixtures__/simple-site/siteConfig.js | 7 ++++ test/load/config.test.js | 35 +++++++++++++++++++ 6 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 test/jest.config.js create mode 100644 test/load/__fixtures__/bad-site/siteConfig.js create mode 100644 test/load/__fixtures__/simple-site/siteConfig.js create mode 100644 test/load/config.test.js diff --git a/lib/load/config.js b/lib/load/config.js index 557edef3e2..3303e4f438 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -10,5 +10,17 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { if (fs.existsSync(configPath)) { config = require(configPath); // eslint-disable-line } + + const requiredFields = [ + 'title', + 'tagline', + 'organizationName', + 'projectName', + 'baseUrl' + ]; + const missingFields = requiredFields.filter(field => !config[field]); + if (missingFields && missingFields.length > 0) { + throw new Error(missingFields.join(', ') + ' are missing in siteConfig.js'); + } return config; }; diff --git a/package.json b/package.json index ab056b14b9..3a04e668f0 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "node bin/munseo build website", "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", - "test": "jest" + "test": "jest --config test/jest.config.js" }, "repository": { "type": "git", @@ -75,12 +75,5 @@ }, "engines": { "node": ">=8" - }, - "jest": { - "testPathIgnorePatterns": [ - "/node_modules/", - "__fixtures__" - ], - "testEnvironment": "node" } } diff --git a/test/jest.config.js b/test/jest.config.js new file mode 100644 index 0000000000..cb505b774e --- /dev/null +++ b/test/jest.config.js @@ -0,0 +1,12 @@ +const path = require('path'); + +module.exports = { + rootDir: path.resolve(__dirname, '..'), + verbose: true, + testURL: 'http://localhost/', + testEnvironment: 'node', + moduleNameMapper: { + '^@lib/(.*)$': '/lib/$1' + }, + testPathIgnorePatterns: ['/node_modules/', '__fixtures__'] +}; diff --git a/test/load/__fixtures__/bad-site/siteConfig.js b/test/load/__fixtures__/bad-site/siteConfig.js new file mode 100644 index 0000000000..58d75f1d57 --- /dev/null +++ b/test/load/__fixtures__/bad-site/siteConfig.js @@ -0,0 +1,4 @@ +module.exports = { + title: 'Munseo', + baseUrl: '/' +}; diff --git a/test/load/__fixtures__/simple-site/siteConfig.js b/test/load/__fixtures__/simple-site/siteConfig.js new file mode 100644 index 0000000000..0e52974bd7 --- /dev/null +++ b/test/load/__fixtures__/simple-site/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/load/config.test.js b/test/load/config.test.js new file mode 100644 index 0000000000..381ebbe0aa --- /dev/null +++ b/test/load/config.test.js @@ -0,0 +1,35 @@ +import path from 'path'; +import loadConfig from '@lib/load/config.js'; + +describe('loadConfig', () => { + test('website with valid siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); + const config = loadConfig(siteDir); + expect(config).toEqual({ + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }); + expect(config).not.toEqual({}); + }); + + test('website with incomplete siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'bad-site'); + expect(() => { + loadConfig(siteDir); + }).toThrowErrorMatchingInlineSnapshot( + `"tagline, organizationName, projectName are missing in siteConfig.js"` + ); + }); + + test('website with no siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'nonExisting'); + expect(() => { + loadConfig(siteDir); + }).toThrowErrorMatchingInlineSnapshot( + `"title, tagline, organizationName, projectName, baseUrl are missing in siteConfig.js"` + ); + }); +}); From d80a2555c0c4491cb2751f5f901c692b418a787f Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 10 Aug 2018 15:04:58 +0800 Subject: [PATCH 070/135] test: load docs --- test/load/__fixtures__/simple-docs/foo/bar.md | 66 ++++++++++++++++ test/load/__fixtures__/simple-docs/foo/baz.md | 77 +++++++++++++++++++ test/load/__fixtures__/simple-docs/hello.md | 40 ++++++++++ test/load/__snapshots__/docs.test.js.snap | 24 ++++++ test/load/docs.test.js | 21 +++++ 5 files changed, 228 insertions(+) create mode 100644 test/load/__fixtures__/simple-docs/foo/bar.md create mode 100644 test/load/__fixtures__/simple-docs/foo/baz.md create mode 100644 test/load/__fixtures__/simple-docs/hello.md create mode 100644 test/load/__snapshots__/docs.test.js.snap create mode 100644 test/load/docs.test.js diff --git a/test/load/__fixtures__/simple-docs/foo/bar.md b/test/load/__fixtures__/simple-docs/foo/bar.md new file mode 100644 index 0000000000..9f978009c5 --- /dev/null +++ b/test/load/__fixtures__/simple-docs/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: bar +title: Bar +--- + +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/load/__fixtures__/simple-docs/foo/baz.md b/test/load/__fixtures__/simple-docs/foo/baz.md new file mode 100644 index 0000000000..add729c51d --- /dev/null +++ b/test/load/__fixtures__/simple-docs/foo/baz.md @@ -0,0 +1,77 @@ +--- +id: baz +title: baz +--- + +## Images + +![Minion](/img/minion.png) +![Stormtroopocat](/img/stormtroopocat.jpg) + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/load/__fixtures__/simple-docs/hello.md b/test/load/__fixtures__/simple-docs/hello.md new file mode 100644 index 0000000000..a392b2ca54 --- /dev/null +++ b/test/load/__fixtures__/simple-docs/hello.md @@ -0,0 +1,40 @@ +--- +id: hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/load/__snapshots__/docs.test.js.snap b/test/load/__snapshots__/docs.test.js.snap new file mode 100644 index 0000000000..8c07385f96 --- /dev/null +++ b/test/load/__snapshots__/docs.test.js.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadDocs simple docs 1`] = ` +Array [ + Object { + "id": "hello", + "path": "/hello", + "source": "hello.md", + "title": "Hello, World !", + }, + Object { + "id": "bar", + "path": "/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + }, + Object { + "id": "baz", + "path": "/foo/baz", + "source": "foo/baz.md", + "title": "baz", + }, +] +`; diff --git a/test/load/docs.test.js b/test/load/docs.test.js new file mode 100644 index 0000000000..bb967074f2 --- /dev/null +++ b/test/load/docs.test.js @@ -0,0 +1,21 @@ +import loadDocs from '@lib/load/docs.js'; +import path from 'path'; + +describe('loadDocs', () => { + test('simple docs', async () => { + const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); + const docsData = await loadDocs(docsDir); + expect(docsData).toMatchSnapshot(); + expect(docsData).not.toBeNull(); + }); + + test('no docs', async () => { + const nonExistingDocsDir = path.join( + __dirname, + '__fixtures__', + 'nonExistingDocs' + ); + const docsData = await loadDocs(nonExistingDocsDir); + expect(docsData).toEqual([]); + }); +}); From cfd11fbb6d06b28eea5ff5c3faa0a396cec24aaf Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 10 Aug 2018 15:26:37 +0800 Subject: [PATCH 071/135] test: utils for load --- lib/load/utils.js | 10 +++++----- test/load/utils.test.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 test/load/utils.test.js diff --git a/lib/load/utils.js b/lib/load/utils.js index 2080afbefa..38b2e5bbf9 100644 --- a/lib/load/utils.js +++ b/lib/load/utils.js @@ -31,13 +31,13 @@ function encodePath(userpath) { } function fileToComponentName(file) { - let str = file.replace(/([A-Z])/g, ' $1'); - if (str.length === 1) { - return str.toUpperCase(); - } + const ext = extRE.exec(file)[1]; + let str = file.replace(extRE, ''); + str = str.replace(/([A-Z])/g, ' $1'); str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); str = str.charAt(0).toUpperCase() + str.slice(1); - return str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase()); + str = str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase()); + return ext ? ext.toUpperCase() + str : str; } module.exports = { diff --git a/test/load/utils.test.js b/test/load/utils.test.js new file mode 100644 index 0000000000..c292135d01 --- /dev/null +++ b/test/load/utils.test.js @@ -0,0 +1,38 @@ +import path from 'path'; +import {fileToPath, fileToComponentName} from '@lib/load/utils.js'; + +describe('load utils', () => { + test('fileToComponentName', () => { + const asserts = { + 'index.md': 'MDIndex', + 'hello/index.md': 'MDHelloIndex', + 'foo.md': 'MDFoo', + 'foo-bar.md': 'MDFooBar', + 'index.js': 'JSIndex', + 'foobar.js': 'JSFoobar', + 'docusaurus/index.js': 'JSDocusaurusIndex', + '234.md': 'MD234', + '2018-07-08-test.md': 'MD20180708Test', + '%asd.md': 'MDAsd' + }; + Object.keys(asserts).forEach(file => { + expect(fileToComponentName(file)).toBe(asserts[file]); + }); + }); + + test('fileToPath', () => { + const asserts = { + 'index.md': '/', + 'hello/index.md': '/hello/', + 'foo.md': '/foo', + 'foo/bar.md': '/foo/bar', + 'index.js': '/', + 'hello/index.js': '/hello/', + 'foo.js': '/foo', + 'foo/bar.js': '/foo/bar' + }; + Object.keys(asserts).forEach(file => { + expect(fileToPath(file)).toBe(asserts[file]); + }); + }); +}); From 8f493605ad050eb7e73ebe48a762ee37bf0c2dc8 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 01:03:46 +0800 Subject: [PATCH 072/135] test: load pages --- .../load/__fixtures__/simple-pages/bar/baz.js | 1 + test/load/__fixtures__/simple-pages/foo.js | 1 + .../__fixtures__/simple-pages/foo/index.js | 1 + test/load/__fixtures__/simple-pages/index.js | 1 + test/load/__snapshots__/pages.test.js.snap | 22 +++++++++++++++++++ test/load/pages.test.js | 17 ++++++++++++++ 6 files changed, 43 insertions(+) create mode 100644 test/load/__fixtures__/simple-pages/bar/baz.js create mode 100644 test/load/__fixtures__/simple-pages/foo.js create mode 100644 test/load/__fixtures__/simple-pages/foo/index.js create mode 100644 test/load/__fixtures__/simple-pages/index.js create mode 100644 test/load/__snapshots__/pages.test.js.snap create mode 100644 test/load/pages.test.js diff --git a/test/load/__fixtures__/simple-pages/bar/baz.js b/test/load/__fixtures__/simple-pages/bar/baz.js new file mode 100644 index 0000000000..7bff47ab5f --- /dev/null +++ b/test/load/__fixtures__/simple-pages/bar/baz.js @@ -0,0 +1 @@ +export default () =>
    Baz
    ; diff --git a/test/load/__fixtures__/simple-pages/foo.js b/test/load/__fixtures__/simple-pages/foo.js new file mode 100644 index 0000000000..cc15b8d603 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/foo.js @@ -0,0 +1 @@ +export default () =>
    Foo
    ; diff --git a/test/load/__fixtures__/simple-pages/foo/index.js b/test/load/__fixtures__/simple-pages/foo/index.js new file mode 100644 index 0000000000..64e2a041e5 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/foo/index.js @@ -0,0 +1 @@ +export default () =>
    Foo in subfolder
    ; diff --git a/test/load/__fixtures__/simple-pages/index.js b/test/load/__fixtures__/simple-pages/index.js new file mode 100644 index 0000000000..8d3c74cde7 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/index.js @@ -0,0 +1 @@ +export default () =>
    Index
    ; diff --git a/test/load/__snapshots__/pages.test.js.snap b/test/load/__snapshots__/pages.test.js.snap new file mode 100644 index 0000000000..8fcb8818fc --- /dev/null +++ b/test/load/__snapshots__/pages.test.js.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadPages valid pages 1`] = ` +Array [ + Object { + "path": "/foo", + "source": "foo.js", + }, + Object { + "path": "/", + "source": "index.js", + }, + Object { + "path": "/bar/baz", + "source": "bar/baz.js", + }, + Object { + "path": "/foo/", + "source": "foo/index.js", + }, +] +`; diff --git a/test/load/pages.test.js b/test/load/pages.test.js new file mode 100644 index 0000000000..b2d5e59004 --- /dev/null +++ b/test/load/pages.test.js @@ -0,0 +1,17 @@ +import loadPages from '@lib/load/pages.js'; +import path from 'path'; + +describe('loadPages', () => { + test('valid pages', async () => { + const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); + const pagesData = await loadPages(pagesDir); + expect(pagesData).toMatchSnapshot(); + expect(pagesData).not.toBeNull(); + }); + + test('invalid pages', async () => { + const nonExistingDir = path.join(__dirname, '__fixtures__', 'nonExisting'); + const pagesData = await loadPages(nonExistingDir); + expect(pagesData).toEqual([]); + }); +}); From 084063eabef48a0238d3c024afff78a192c10436 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 01:33:24 +0800 Subject: [PATCH 073/135] chore: eslint & prettier nits --- lib/commands/start.js | 3 + lib/load/config.js | 2 +- lib/load/utils.js | 2 +- lib/webpack/prod.js | 4 +- test/jest.config.js | 24 +++--- test/load/__fixtures__/bad-site/siteConfig.js | 8 +- .../load/__fixtures__/simple-pages/bar/baz.js | 4 +- test/load/__fixtures__/simple-pages/foo.js | 4 +- .../__fixtures__/simple-pages/foo/index.js | 4 +- test/load/__fixtures__/simple-pages/index.js | 4 +- .../__fixtures__/simple-site/siteConfig.js | 14 ++-- test/load/config.test.js | 70 ++++++++--------- test/load/docs.test.js | 42 +++++------ test/load/pages.test.js | 34 ++++----- test/load/utils.test.js | 75 +++++++++---------- 15 files changed, 152 insertions(+), 142 deletions(-) diff --git a/lib/commands/start.js b/lib/commands/start.js index cc373b79b4..a42804ad2b 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -20,6 +20,9 @@ async function getPort(reqPort) { } module.exports = async function start(siteDir, cliOptions = {}) { + console.log('Start command invoked ...'); + console.log(cliOptions); + // Process all related files as a prop const props = await load(siteDir); diff --git a/lib/load/config.js b/lib/load/config.js index 3303e4f438..b5269b5a2f 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -20,7 +20,7 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { ]; const missingFields = requiredFields.filter(field => !config[field]); if (missingFields && missingFields.length > 0) { - throw new Error(missingFields.join(', ') + ' are missing in siteConfig.js'); + throw new Error(`${missingFields.join(', ')} are missing in siteConfig.js`); } return config; }; diff --git a/lib/load/utils.js b/lib/load/utils.js index 38b2e5bbf9..05be648bb2 100644 --- a/lib/load/utils.js +++ b/lib/load/utils.js @@ -37,7 +37,7 @@ function fileToComponentName(file) { str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); str = str.charAt(0).toUpperCase() + str.slice(1); str = str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase()); - return ext ? ext.toUpperCase() + str : str; + return ext ? ext.toUpperCase() + str : str; } module.exports = { diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index 2dcb8e91a6..4e5a8d5944 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -30,9 +30,9 @@ module.exports = function createProdConfig(props) { ]); // show compilation progress bar and build time config.plugin('niceLog').use(webpackNiceLog, [{name: 'Production'}]); - + // Webpack Bundle Analyzer to check which causes huge bundle size config.plugin('bundleAnalyzer').use(bundleAnalyzer); - + return config; }; diff --git a/test/jest.config.js b/test/jest.config.js index cb505b774e..7c7392384c 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -1,12 +1,12 @@ -const path = require('path'); - -module.exports = { - rootDir: path.resolve(__dirname, '..'), - verbose: true, - testURL: 'http://localhost/', - testEnvironment: 'node', - moduleNameMapper: { - '^@lib/(.*)$': '/lib/$1' - }, - testPathIgnorePatterns: ['/node_modules/', '__fixtures__'] -}; +const path = require('path'); + +module.exports = { + rootDir: path.resolve(__dirname, '..'), + verbose: true, + testURL: 'http://localhost/', + testEnvironment: 'node', + moduleNameMapper: { + '^@lib/(.*)$': '/lib/$1' + }, + testPathIgnorePatterns: ['/node_modules/', '__fixtures__'] +}; diff --git a/test/load/__fixtures__/bad-site/siteConfig.js b/test/load/__fixtures__/bad-site/siteConfig.js index 58d75f1d57..2f57430423 100644 --- a/test/load/__fixtures__/bad-site/siteConfig.js +++ b/test/load/__fixtures__/bad-site/siteConfig.js @@ -1,4 +1,4 @@ -module.exports = { - title: 'Munseo', - baseUrl: '/' -}; +module.exports = { + title: 'Munseo', + baseUrl: '/' +}; diff --git a/test/load/__fixtures__/simple-pages/bar/baz.js b/test/load/__fixtures__/simple-pages/bar/baz.js index 7bff47ab5f..75a8c70015 100644 --- a/test/load/__fixtures__/simple-pages/bar/baz.js +++ b/test/load/__fixtures__/simple-pages/bar/baz.js @@ -1 +1,3 @@ -export default () =>
    Baz
    ; +import React from 'react'; + +export default () =>
    Baz
    ; diff --git a/test/load/__fixtures__/simple-pages/foo.js b/test/load/__fixtures__/simple-pages/foo.js index cc15b8d603..3b52ec615c 100644 --- a/test/load/__fixtures__/simple-pages/foo.js +++ b/test/load/__fixtures__/simple-pages/foo.js @@ -1 +1,3 @@ -export default () =>
    Foo
    ; +import React from 'react'; + +export default () =>
    Foo
    ; diff --git a/test/load/__fixtures__/simple-pages/foo/index.js b/test/load/__fixtures__/simple-pages/foo/index.js index 64e2a041e5..5faf67ae13 100644 --- a/test/load/__fixtures__/simple-pages/foo/index.js +++ b/test/load/__fixtures__/simple-pages/foo/index.js @@ -1 +1,3 @@ -export default () =>
    Foo in subfolder
    ; +import React from 'react'; + +export default () =>
    Foo in subfolder
    ; diff --git a/test/load/__fixtures__/simple-pages/index.js b/test/load/__fixtures__/simple-pages/index.js index 8d3c74cde7..13063810a7 100644 --- a/test/load/__fixtures__/simple-pages/index.js +++ b/test/load/__fixtures__/simple-pages/index.js @@ -1 +1,3 @@ -export default () =>
    Index
    ; +import React from 'react'; + +export default () =>
    Index
    ; diff --git a/test/load/__fixtures__/simple-site/siteConfig.js b/test/load/__fixtures__/simple-site/siteConfig.js index 0e52974bd7..e64b9989cf 100644 --- a/test/load/__fixtures__/simple-site/siteConfig.js +++ b/test/load/__fixtures__/simple-site/siteConfig.js @@ -1,7 +1,7 @@ -module.exports = { - title: 'Hello', - tagline: 'Hello World', - organizationName: 'endiliey', - projectName: 'hello', - baseUrl: '/' -}; +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/load/config.test.js b/test/load/config.test.js index 381ebbe0aa..f0015a0770 100644 --- a/test/load/config.test.js +++ b/test/load/config.test.js @@ -1,35 +1,35 @@ -import path from 'path'; -import loadConfig from '@lib/load/config.js'; - -describe('loadConfig', () => { - test('website with valid siteConfig', () => { - const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); - const config = loadConfig(siteDir); - expect(config).toEqual({ - baseUrl: '/', - organizationName: 'endiliey', - projectName: 'hello', - tagline: 'Hello World', - title: 'Hello' - }); - expect(config).not.toEqual({}); - }); - - test('website with incomplete siteConfig', () => { - const siteDir = path.join(__dirname, '__fixtures__', 'bad-site'); - expect(() => { - loadConfig(siteDir); - }).toThrowErrorMatchingInlineSnapshot( - `"tagline, organizationName, projectName are missing in siteConfig.js"` - ); - }); - - test('website with no siteConfig', () => { - const siteDir = path.join(__dirname, '__fixtures__', 'nonExisting'); - expect(() => { - loadConfig(siteDir); - }).toThrowErrorMatchingInlineSnapshot( - `"title, tagline, organizationName, projectName, baseUrl are missing in siteConfig.js"` - ); - }); -}); +import path from 'path'; +import loadConfig from '@lib/load/config'; + +describe('loadConfig', () => { + test('website with valid siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); + const config = loadConfig(siteDir); + expect(config).toEqual({ + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }); + expect(config).not.toEqual({}); + }); + + test('website with incomplete siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'bad-site'); + expect(() => { + loadConfig(siteDir); + }).toThrowErrorMatchingInlineSnapshot( + `"tagline, organizationName, projectName are missing in siteConfig.js"` + ); + }); + + test('website with no siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'nonExisting'); + expect(() => { + loadConfig(siteDir); + }).toThrowErrorMatchingInlineSnapshot( + `"title, tagline, organizationName, projectName, baseUrl are missing in siteConfig.js"` + ); + }); +}); diff --git a/test/load/docs.test.js b/test/load/docs.test.js index bb967074f2..01588e12f9 100644 --- a/test/load/docs.test.js +++ b/test/load/docs.test.js @@ -1,21 +1,21 @@ -import loadDocs from '@lib/load/docs.js'; -import path from 'path'; - -describe('loadDocs', () => { - test('simple docs', async () => { - const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); - const docsData = await loadDocs(docsDir); - expect(docsData).toMatchSnapshot(); - expect(docsData).not.toBeNull(); - }); - - test('no docs', async () => { - const nonExistingDocsDir = path.join( - __dirname, - '__fixtures__', - 'nonExistingDocs' - ); - const docsData = await loadDocs(nonExistingDocsDir); - expect(docsData).toEqual([]); - }); -}); +import loadDocs from '@lib/load/docs'; +import path from 'path'; + +describe('loadDocs', () => { + test('simple docs', async () => { + const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); + const docsData = await loadDocs(docsDir); + expect(docsData).toMatchSnapshot(); + expect(docsData).not.toBeNull(); + }); + + test('no docs', async () => { + const nonExistingDocsDir = path.join( + __dirname, + '__fixtures__', + 'nonExistingDocs' + ); + const docsData = await loadDocs(nonExistingDocsDir); + expect(docsData).toEqual([]); + }); +}); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index b2d5e59004..7a76e76a82 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -1,17 +1,17 @@ -import loadPages from '@lib/load/pages.js'; -import path from 'path'; - -describe('loadPages', () => { - test('valid pages', async () => { - const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - const pagesData = await loadPages(pagesDir); - expect(pagesData).toMatchSnapshot(); - expect(pagesData).not.toBeNull(); - }); - - test('invalid pages', async () => { - const nonExistingDir = path.join(__dirname, '__fixtures__', 'nonExisting'); - const pagesData = await loadPages(nonExistingDir); - expect(pagesData).toEqual([]); - }); -}); +import loadPages from '@lib/load/pages'; +import path from 'path'; + +describe('loadPages', () => { + test('valid pages', async () => { + const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); + const pagesData = await loadPages(pagesDir); + expect(pagesData).toMatchSnapshot(); + expect(pagesData).not.toBeNull(); + }); + + test('invalid pages', async () => { + const nonExistingDir = path.join(__dirname, '__fixtures__', 'nonExisting'); + const pagesData = await loadPages(nonExistingDir); + expect(pagesData).toEqual([]); + }); +}); diff --git a/test/load/utils.test.js b/test/load/utils.test.js index c292135d01..7012f191bd 100644 --- a/test/load/utils.test.js +++ b/test/load/utils.test.js @@ -1,38 +1,37 @@ -import path from 'path'; -import {fileToPath, fileToComponentName} from '@lib/load/utils.js'; - -describe('load utils', () => { - test('fileToComponentName', () => { - const asserts = { - 'index.md': 'MDIndex', - 'hello/index.md': 'MDHelloIndex', - 'foo.md': 'MDFoo', - 'foo-bar.md': 'MDFooBar', - 'index.js': 'JSIndex', - 'foobar.js': 'JSFoobar', - 'docusaurus/index.js': 'JSDocusaurusIndex', - '234.md': 'MD234', - '2018-07-08-test.md': 'MD20180708Test', - '%asd.md': 'MDAsd' - }; - Object.keys(asserts).forEach(file => { - expect(fileToComponentName(file)).toBe(asserts[file]); - }); - }); - - test('fileToPath', () => { - const asserts = { - 'index.md': '/', - 'hello/index.md': '/hello/', - 'foo.md': '/foo', - 'foo/bar.md': '/foo/bar', - 'index.js': '/', - 'hello/index.js': '/hello/', - 'foo.js': '/foo', - 'foo/bar.js': '/foo/bar' - }; - Object.keys(asserts).forEach(file => { - expect(fileToPath(file)).toBe(asserts[file]); - }); - }); -}); +import {fileToPath, fileToComponentName} from '@lib/load/utils'; + +describe('load utils', () => { + test('fileToComponentName', () => { + const asserts = { + 'index.md': 'MDIndex', + 'hello/index.md': 'MDHelloIndex', + 'foo.md': 'MDFoo', + 'foo-bar.md': 'MDFooBar', + 'index.js': 'JSIndex', + 'foobar.js': 'JSFoobar', + 'docusaurus/index.js': 'JSDocusaurusIndex', + '234.md': 'MD234', + '2018-07-08-test.md': 'MD20180708Test', + '%asd.md': 'MDAsd' + }; + Object.keys(asserts).forEach(file => { + expect(fileToComponentName(file)).toBe(asserts[file]); + }); + }); + + test('fileToPath', () => { + const asserts = { + 'index.md': '/', + 'hello/index.md': '/hello/', + 'foo.md': '/foo', + 'foo/bar.md': '/foo/bar', + 'index.js': '/', + 'hello/index.js': '/hello/', + 'foo.js': '/foo', + 'foo/bar.js': '/foo/bar' + }; + Object.keys(asserts).forEach(file => { + expect(fileToPath(file)).toBe(asserts[file]); + }); + }); +}); From 8a5807418d47f77469638dc0677e65fadf5dea43 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 01:34:35 +0800 Subject: [PATCH 074/135] test: genRoutesConfig --- lib/load/routes.js | 2 +- test/load/__snapshots__/routes.test.js.snap | 169 ++++++++++++++++++++ test/load/routes.test.js | 39 +++++ 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 test/load/__snapshots__/routes.test.js.snap create mode 100644 test/load/routes.test.js diff --git a/lib/load/routes.js b/lib/load/routes.js index 908baa2d73..c84193cc99 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,6 +1,6 @@ const {fileToComponentName} = require('./utils'); -async function genRoutesConfig({docsData, pagesData}) { +async function genRoutesConfig({docsData = [], pagesData = []}) { function genDocsRoute({path: docsPath, source}) { const componentName = fileToComponentName(source); return ` diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap new file mode 100644 index 0000000000..e0f4c9eff0 --- /dev/null +++ b/test/load/__snapshots__/routes.test.js.snap @@ -0,0 +1,169 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`genRoutesConfig website with no docs/pages 1`] = ` +"import React from 'react'; +import Docs from '@theme/Docs'; +import NotFound from '@theme/NotFound'; + + +const routes = [,, + { + path: '*', + component: NotFound + } +]; +export default routes; +" +`; + +exports[`genRoutesConfig website with only docs 1`] = ` +"import React from 'react'; +import Docs from '@theme/Docs'; +import NotFound from '@theme/NotFound'; + +import MDHello from '@docs/hello.md'; +import MDFooBaz from '@docs/foo/baz.md'; +import MDFooBar from '@docs/foo/bar.md'; +const routes = [ + { + path: \\"/hello\\", + exact: true, + component: () => ( + + + + ) + }, + { + path: \\"/foo/baz\\", + exact: true, + component: () => ( + + + + ) + }, + { + path: \\"/foo/bar\\", + exact: true, + component: () => ( + + + + ) + },, + { + path: '*', + component: NotFound + } +]; +export default routes; +" +`; + +exports[`genRoutesConfig website with only pages 1`] = ` +"import React from 'react'; +import Docs from '@theme/Docs'; +import NotFound from '@theme/NotFound'; +import JSIndex from '@pages/index.js'; +import JSFoo from '@pages/foo.js'; +import JSBarBaz from '@pages/bar/baz.js'; +import JSFooIndex from '@pages/foo/index.js'; + +const routes = [, + { + path: \\"/\\", + exact: true, + component: JSIndex + }, + { + path: \\"/foo\\", + exact: true, + component: JSFoo + }, + { + path: \\"/bar/baz\\", + exact: true, + component: JSBarBaz + }, + { + path: \\"/foo/\\", + exact: true, + component: JSFooIndex + }, + { + path: '*', + component: NotFound + } +]; +export default routes; +" +`; + +exports[`genRoutesConfig website with pages and docs 1`] = ` +"import React from 'react'; +import Docs from '@theme/Docs'; +import NotFound from '@theme/NotFound'; +import JSFoo from '@pages/foo.js'; +import JSIndex from '@pages/index.js'; +import JSBarBaz from '@pages/bar/baz.js'; +import JSFooIndex from '@pages/foo/index.js'; +import MDHello from '@docs/hello.md'; +import MDFooBar from '@docs/foo/bar.md'; +import MDFooBaz from '@docs/foo/baz.md'; +const routes = [ + { + path: \\"/hello\\", + exact: true, + component: () => ( + + + + ) + }, + { + path: \\"/foo/bar\\", + exact: true, + component: () => ( + + + + ) + }, + { + path: \\"/foo/baz\\", + exact: true, + component: () => ( + + + + ) + }, + { + path: \\"/foo\\", + exact: true, + component: JSFoo + }, + { + path: \\"/\\", + exact: true, + component: JSIndex + }, + { + path: \\"/bar/baz\\", + exact: true, + component: JSBarBaz + }, + { + path: \\"/foo/\\", + exact: true, + component: JSFooIndex + }, + { + path: '*', + component: NotFound + } +]; +export default routes; +" +`; diff --git a/test/load/routes.test.js b/test/load/routes.test.js new file mode 100644 index 0000000000..7022c420a4 --- /dev/null +++ b/test/load/routes.test.js @@ -0,0 +1,39 @@ +import genRoutesConfig from '@lib/load/routes'; +import loadDocs from '@lib/load/docs'; +import loadPages from '@lib/load/pages'; +import path from 'path'; + +describe('genRoutesConfig', () => { + const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); + const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); + + test('website with pages and docs', async () => { + const props = { + docsData: await loadDocs(docsDir), + pagesData: await loadPages(pagesDir) + }; + const routes = await genRoutesConfig(props); + expect(routes).toMatchSnapshot(); + }); + + test('website with only pages', async () => { + const props = { + pagesData: await loadPages(pagesDir) + }; + const routes = await genRoutesConfig(props); + expect(routes).toMatchSnapshot(); + }); + + test('website with only docs', async () => { + const props = { + docsData: await loadDocs(docsDir) + }; + const routes = await genRoutesConfig(props); + expect(routes).toMatchSnapshot(); + }); + + test('website with no docs/pages', async () => { + const routes = await genRoutesConfig({}); + expect(routes).toMatchSnapshot(); + }); +}); From 80204b56178ccb261e9560c09232571216de07ba Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 02:50:11 +0800 Subject: [PATCH 075/135] chore: remove bundle analyzer --- lib/webpack/prod.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index 4e5a8d5944..7c402ae208 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -1,7 +1,6 @@ const path = require('path'); const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); -const bundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const createBaseConfig = require('./base'); module.exports = function createProdConfig(props) { @@ -31,8 +30,5 @@ module.exports = function createProdConfig(props) { // show compilation progress bar and build time config.plugin('niceLog').use(webpackNiceLog, [{name: 'Production'}]); - // Webpack Bundle Analyzer to check which causes huge bundle size - config.plugin('bundleAnalyzer').use(bundleAnalyzer); - return config; }; From a4cc782858f9c7045b3eff4481048ee43be4ddef Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 02:50:41 +0800 Subject: [PATCH 076/135] test: test compile dev/prod webpack config --- .../custom-website/pages}/bar/baz.js | 0 .../custom-website/pages}/foo.js | 0 .../custom-website/pages}/foo/index.js | 0 .../custom-website/pages}/index.js | 0 .../__fixtures__/custom-website/siteConfig.js | 7 +++ .../docs}/foo/bar.md | 0 .../docs}/foo/baz.md | 0 .../docs}/hello.md | 0 .../simple-website/pages/bar/baz.js | 3 ++ test/__fixtures__/simple-website/pages/foo.js | 3 ++ .../simple-website/pages/foo/index.js | 3 ++ .../simple-website/pages/index.js | 3 ++ .../__fixtures__/simple-website/siteConfig.js | 7 +++ test/loadSetup.js | 19 ++++++++ test/webpack/index.test.js | 48 +++++++++++++++++++ 15 files changed, 93 insertions(+) rename test/{load/__fixtures__/simple-pages => __fixtures__/custom-website/pages}/bar/baz.js (100%) rename test/{load/__fixtures__/simple-pages => __fixtures__/custom-website/pages}/foo.js (100%) rename test/{load/__fixtures__/simple-pages => __fixtures__/custom-website/pages}/foo/index.js (100%) rename test/{load/__fixtures__/simple-pages => __fixtures__/custom-website/pages}/index.js (100%) create mode 100644 test/__fixtures__/custom-website/siteConfig.js rename test/{load/__fixtures__/simple-docs => __fixtures__/docs}/foo/bar.md (100%) rename test/{load/__fixtures__/simple-docs => __fixtures__/docs}/foo/baz.md (100%) rename test/{load/__fixtures__/simple-docs => __fixtures__/docs}/hello.md (100%) create mode 100644 test/__fixtures__/simple-website/pages/bar/baz.js create mode 100644 test/__fixtures__/simple-website/pages/foo.js create mode 100644 test/__fixtures__/simple-website/pages/foo/index.js create mode 100644 test/__fixtures__/simple-website/pages/index.js create mode 100644 test/__fixtures__/simple-website/siteConfig.js create mode 100644 test/loadSetup.js create mode 100644 test/webpack/index.test.js diff --git a/test/load/__fixtures__/simple-pages/bar/baz.js b/test/__fixtures__/custom-website/pages/bar/baz.js similarity index 100% rename from test/load/__fixtures__/simple-pages/bar/baz.js rename to test/__fixtures__/custom-website/pages/bar/baz.js diff --git a/test/load/__fixtures__/simple-pages/foo.js b/test/__fixtures__/custom-website/pages/foo.js similarity index 100% rename from test/load/__fixtures__/simple-pages/foo.js rename to test/__fixtures__/custom-website/pages/foo.js diff --git a/test/load/__fixtures__/simple-pages/foo/index.js b/test/__fixtures__/custom-website/pages/foo/index.js similarity index 100% rename from test/load/__fixtures__/simple-pages/foo/index.js rename to test/__fixtures__/custom-website/pages/foo/index.js diff --git a/test/load/__fixtures__/simple-pages/index.js b/test/__fixtures__/custom-website/pages/index.js similarity index 100% rename from test/load/__fixtures__/simple-pages/index.js rename to test/__fixtures__/custom-website/pages/index.js diff --git a/test/__fixtures__/custom-website/siteConfig.js b/test/__fixtures__/custom-website/siteConfig.js new file mode 100644 index 0000000000..3c5b2a6f42 --- /dev/null +++ b/test/__fixtures__/custom-website/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Sakura', + tagline: 'This is not an ordinary site', + organizationName: 'endiliey', + projectName: 'sakura', + baseUrl: '/sakura/' +}; diff --git a/test/load/__fixtures__/simple-docs/foo/bar.md b/test/__fixtures__/docs/foo/bar.md similarity index 100% rename from test/load/__fixtures__/simple-docs/foo/bar.md rename to test/__fixtures__/docs/foo/bar.md diff --git a/test/load/__fixtures__/simple-docs/foo/baz.md b/test/__fixtures__/docs/foo/baz.md similarity index 100% rename from test/load/__fixtures__/simple-docs/foo/baz.md rename to test/__fixtures__/docs/foo/baz.md diff --git a/test/load/__fixtures__/simple-docs/hello.md b/test/__fixtures__/docs/hello.md similarity index 100% rename from test/load/__fixtures__/simple-docs/hello.md rename to test/__fixtures__/docs/hello.md diff --git a/test/__fixtures__/simple-website/pages/bar/baz.js b/test/__fixtures__/simple-website/pages/bar/baz.js new file mode 100644 index 0000000000..75a8c70015 --- /dev/null +++ b/test/__fixtures__/simple-website/pages/bar/baz.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Baz
    ; diff --git a/test/__fixtures__/simple-website/pages/foo.js b/test/__fixtures__/simple-website/pages/foo.js new file mode 100644 index 0000000000..3b52ec615c --- /dev/null +++ b/test/__fixtures__/simple-website/pages/foo.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Foo
    ; diff --git a/test/__fixtures__/simple-website/pages/foo/index.js b/test/__fixtures__/simple-website/pages/foo/index.js new file mode 100644 index 0000000000..5faf67ae13 --- /dev/null +++ b/test/__fixtures__/simple-website/pages/foo/index.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Foo in subfolder
    ; diff --git a/test/__fixtures__/simple-website/pages/index.js b/test/__fixtures__/simple-website/pages/index.js new file mode 100644 index 0000000000..13063810a7 --- /dev/null +++ b/test/__fixtures__/simple-website/pages/index.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Index
    ; diff --git a/test/__fixtures__/simple-website/siteConfig.js b/test/__fixtures__/simple-website/siteConfig.js new file mode 100644 index 0000000000..e64b9989cf --- /dev/null +++ b/test/__fixtures__/simple-website/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/loadSetup.js b/test/loadSetup.js new file mode 100644 index 0000000000..2aa6995b88 --- /dev/null +++ b/test/loadSetup.js @@ -0,0 +1,19 @@ +import path from 'path'; +import load from '@lib/load'; + +// Helper methods to setup dummy/ fake projects +const loadSetup = async name => { + const simpleWebsite = path.join(__dirname, '__fixtures__', 'simple-website'); + const customWebsite = path.join(__dirname, '__fixtures__', 'custom-website'); + + switch (name) { + case 'simple': + return await load(simpleWebsite); + case 'custom': + return await load(customWebsite); + default: + return {}; + } +}; + +export default loadSetup; diff --git a/test/webpack/index.test.js b/test/webpack/index.test.js new file mode 100644 index 0000000000..d9fe538fe3 --- /dev/null +++ b/test/webpack/index.test.js @@ -0,0 +1,48 @@ +import webpack from 'webpack'; +import path from 'path'; +import createBaseConfig from '@lib/webpack/base'; +import createDevConfig from '@lib/webpack/dev'; +import createProdConfig from '@lib/webpack/prod'; +import loadSetup from '../loadSetup'; + +// webpack compiler helper function +function compile(config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err || stats.hasErrors()) { + reject(new Error(`Failed to compile with errors`)); + } + resolve('Compiled successfully'); + }); + }); +} + +describe('webpack', () => { + test('dev simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('dev custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('prod simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('prod custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); +}); From 15ce4a95e22539e711a16c91e702f2116abfdf38 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 02:54:34 +0800 Subject: [PATCH 077/135] chore: eslint & prettier nits --- .eslintignore | 4 +- package.json | 1 - test/loadSetup.js | 38 +++++++-------- test/webpack/index.test.js | 94 +++++++++++++++++++------------------- 4 files changed, 68 insertions(+), 69 deletions(-) diff --git a/.eslintignore b/.eslintignore index dc9b2375c7..5cc1873034 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ -generated \ No newline at end of file +generated +__fixtures__ +dist \ No newline at end of file diff --git a/package.json b/package.json index 3a04e668f0..011398767d 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,6 @@ "semver": "^5.5.0", "static-site-generator-webpack-plugin": "^3.4.1", "webpack": "^4.16.3", - "webpack-bundle-analyzer": "^2.13.1", "webpack-chain": "^4.8.0", "webpack-nicelog": "^2.2.1", "webpack-serve": "^2.0.2" diff --git a/test/loadSetup.js b/test/loadSetup.js index 2aa6995b88..d16f447c38 100644 --- a/test/loadSetup.js +++ b/test/loadSetup.js @@ -1,19 +1,19 @@ -import path from 'path'; -import load from '@lib/load'; - -// Helper methods to setup dummy/ fake projects -const loadSetup = async name => { - const simpleWebsite = path.join(__dirname, '__fixtures__', 'simple-website'); - const customWebsite = path.join(__dirname, '__fixtures__', 'custom-website'); - - switch (name) { - case 'simple': - return await load(simpleWebsite); - case 'custom': - return await load(customWebsite); - default: - return {}; - } -}; - -export default loadSetup; +import path from 'path'; +import load from '@lib/load'; + +// Helper methods to setup dummy/ fake projects +const loadSetup = async name => { + const simpleWebsite = path.join(__dirname, '__fixtures__', 'simple-website'); + const customWebsite = path.join(__dirname, '__fixtures__', 'custom-website'); + + switch (name) { + case 'simple': + return load(simpleWebsite); + case 'custom': + return load(customWebsite); + default: + return {}; + } +}; + +export default loadSetup; diff --git a/test/webpack/index.test.js b/test/webpack/index.test.js index d9fe538fe3..568e3126af 100644 --- a/test/webpack/index.test.js +++ b/test/webpack/index.test.js @@ -1,48 +1,46 @@ -import webpack from 'webpack'; -import path from 'path'; -import createBaseConfig from '@lib/webpack/base'; -import createDevConfig from '@lib/webpack/dev'; -import createProdConfig from '@lib/webpack/prod'; -import loadSetup from '../loadSetup'; - -// webpack compiler helper function -function compile(config) { - return new Promise((resolve, reject) => { - webpack(config, (err, stats) => { - if (err || stats.hasErrors()) { - reject(new Error(`Failed to compile with errors`)); - } - resolve('Compiled successfully'); - }); - }); -} - -describe('webpack', () => { - test('dev simple', async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); - - test('dev custom', async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); - - test('prod simple', async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); - - test('prod custom', async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); -}); +import webpack from 'webpack'; +import createDevConfig from '@lib/webpack/dev'; +import createProdConfig from '@lib/webpack/prod'; +import loadSetup from '../loadSetup'; + +// webpack compiler helper function +function compile(config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err || stats.hasErrors()) { + reject(new Error(`Failed to compile with errors`)); + } + resolve('Compiled successfully'); + }); + }); +} + +describe('webpack', () => { + test('dev simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('dev custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('prod simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); + + test('prod custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }); +}); From 0f28b6f311c9d4a74fa1480561c7311128b0d10c Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 14:22:50 +0800 Subject: [PATCH 078/135] test: fix load test --- lib/load/routes.js | 4 +- test/load/__fixtures__/simple-docs/foo/bar.md | 66 ++++++++++++++ test/load/__fixtures__/simple-docs/foo/baz.md | 77 ++++++++++++++++ test/load/__fixtures__/simple-docs/hello.md | 40 +++++++++ .../load/__fixtures__/simple-pages/bar/baz.js | 3 + test/load/__fixtures__/simple-pages/foo.js | 3 + .../__fixtures__/simple-pages/foo/index.js | 3 + test/load/__fixtures__/simple-pages/index.js | 3 + test/load/__snapshots__/routes.test.js.snap | 90 ++++--------------- 9 files changed, 213 insertions(+), 76 deletions(-) create mode 100644 test/load/__fixtures__/simple-docs/foo/bar.md create mode 100644 test/load/__fixtures__/simple-docs/foo/baz.md create mode 100644 test/load/__fixtures__/simple-docs/hello.md create mode 100644 test/load/__fixtures__/simple-pages/bar/baz.js create mode 100644 test/load/__fixtures__/simple-pages/foo.js create mode 100644 test/load/__fixtures__/simple-pages/foo/index.js create mode 100644 test/load/__fixtures__/simple-pages/index.js diff --git a/lib/load/routes.js b/lib/load/routes.js index c84193cc99..2b6f48fd60 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -7,8 +7,8 @@ async function genRoutesConfig({docsData = [], pagesData = []}) { { path: ${JSON.stringify(docsPath)}, exact: true, - component: () => ( - + component: (props) => ( + <${componentName} /> ) diff --git a/test/load/__fixtures__/simple-docs/foo/bar.md b/test/load/__fixtures__/simple-docs/foo/bar.md new file mode 100644 index 0000000000..9f978009c5 --- /dev/null +++ b/test/load/__fixtures__/simple-docs/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: bar +title: Bar +--- + +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/load/__fixtures__/simple-docs/foo/baz.md b/test/load/__fixtures__/simple-docs/foo/baz.md new file mode 100644 index 0000000000..add729c51d --- /dev/null +++ b/test/load/__fixtures__/simple-docs/foo/baz.md @@ -0,0 +1,77 @@ +--- +id: baz +title: baz +--- + +## Images + +![Minion](/img/minion.png) +![Stormtroopocat](/img/stormtroopocat.jpg) + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/load/__fixtures__/simple-docs/hello.md b/test/load/__fixtures__/simple-docs/hello.md new file mode 100644 index 0000000000..a392b2ca54 --- /dev/null +++ b/test/load/__fixtures__/simple-docs/hello.md @@ -0,0 +1,40 @@ +--- +id: hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/load/__fixtures__/simple-pages/bar/baz.js b/test/load/__fixtures__/simple-pages/bar/baz.js new file mode 100644 index 0000000000..75a8c70015 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/bar/baz.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Baz
    ; diff --git a/test/load/__fixtures__/simple-pages/foo.js b/test/load/__fixtures__/simple-pages/foo.js new file mode 100644 index 0000000000..3b52ec615c --- /dev/null +++ b/test/load/__fixtures__/simple-pages/foo.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Foo
    ; diff --git a/test/load/__fixtures__/simple-pages/foo/index.js b/test/load/__fixtures__/simple-pages/foo/index.js new file mode 100644 index 0000000000..5faf67ae13 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/foo/index.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Foo in subfolder
    ; diff --git a/test/load/__fixtures__/simple-pages/index.js b/test/load/__fixtures__/simple-pages/index.js new file mode 100644 index 0000000000..13063810a7 --- /dev/null +++ b/test/load/__fixtures__/simple-pages/index.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
    Index
    ; diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap index e0f4c9eff0..075ce45f36 100644 --- a/test/load/__snapshots__/routes.test.js.snap +++ b/test/load/__snapshots__/routes.test.js.snap @@ -21,37 +21,8 @@ exports[`genRoutesConfig website with only docs 1`] = ` import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; -import MDHello from '@docs/hello.md'; -import MDFooBaz from '@docs/foo/baz.md'; -import MDFooBar from '@docs/foo/bar.md'; -const routes = [ - { - path: \\"/hello\\", - exact: true, - component: () => ( - - - - ) - }, - { - path: \\"/foo/baz\\", - exact: true, - component: () => ( - - - - ) - }, - { - path: \\"/foo/bar\\", - exact: true, - component: () => ( - - - - ) - },, + +const routes = [,, { path: '*', component: NotFound @@ -65,22 +36,22 @@ exports[`genRoutesConfig website with only pages 1`] = ` "import React from 'react'; import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; -import JSIndex from '@pages/index.js'; import JSFoo from '@pages/foo.js'; +import JSIndex from '@pages/index.js'; import JSBarBaz from '@pages/bar/baz.js'; import JSFooIndex from '@pages/foo/index.js'; const routes = [, - { - path: \\"/\\", - exact: true, - component: JSIndex - }, { path: \\"/foo\\", exact: true, component: JSFoo }, + { + path: \\"/\\", + exact: true, + component: JSIndex + }, { path: \\"/bar/baz\\", exact: true, @@ -106,39 +77,10 @@ import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; import JSFoo from '@pages/foo.js'; import JSIndex from '@pages/index.js'; -import JSBarBaz from '@pages/bar/baz.js'; import JSFooIndex from '@pages/foo/index.js'; -import MDHello from '@docs/hello.md'; -import MDFooBar from '@docs/foo/bar.md'; -import MDFooBaz from '@docs/foo/baz.md'; -const routes = [ - { - path: \\"/hello\\", - exact: true, - component: () => ( - - - - ) - }, - { - path: \\"/foo/bar\\", - exact: true, - component: () => ( - - - - ) - }, - { - path: \\"/foo/baz\\", - exact: true, - component: () => ( - - - - ) - }, +import JSBarBaz from '@pages/bar/baz.js'; + +const routes = [, { path: \\"/foo\\", exact: true, @@ -149,16 +91,16 @@ const routes = [ exact: true, component: JSIndex }, - { - path: \\"/bar/baz\\", - exact: true, - component: JSBarBaz - }, { path: \\"/foo/\\", exact: true, component: JSFooIndex }, + { + path: \\"/bar/baz\\", + exact: true, + component: JSBarBaz + }, { path: '*', component: NotFound From a4f0ed7c94b1e5d75810abe179fa4f110caee663 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 14:23:11 +0800 Subject: [PATCH 079/135] test: more timeout for webpack compile test --- test/webpack/index.test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/webpack/index.test.js b/test/webpack/index.test.js index 568e3126af..d86142588c 100644 --- a/test/webpack/index.test.js +++ b/test/webpack/index.test.js @@ -16,31 +16,33 @@ function compile(config) { } describe('webpack', () => { + const timeOut = 10000; // 10 seconds + test('dev simple', async () => { console.log = jest.fn(); const props = await loadSetup('simple'); const config = createDevConfig(props).toConfig(); return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); + }, timeOut); test('dev custom', async () => { console.log = jest.fn(); const props = await loadSetup('custom'); const config = createDevConfig(props).toConfig(); return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); + }, timeOut); test('prod simple', async () => { console.log = jest.fn(); const props = await loadSetup('simple'); const config = createProdConfig(props).toConfig(); return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); + }, timeOut); test('prod custom', async () => { console.log = jest.fn(); const props = await loadSetup('custom'); const config = createProdConfig(props).toConfig(); return expect(compile(config)).resolves.toBe('Compiled successfully'); - }); + }, timeOut); }); From f07e7791fac5f47ba7a7af981578d0265ce6958d Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 15:19:53 +0800 Subject: [PATCH 080/135] test: compile webpack config for dev and prod --- .prettierignore | 3 +++ test/webpack/base.test.js | 29 +++++++++++++++++++++++ test/webpack/compile.js | 12 ++++++++++ test/webpack/index.test.js | 48 -------------------------------------- test/webpack/prod.test.js | 28 ++++++++++++++++++++++ 5 files changed, 72 insertions(+), 48 deletions(-) create mode 100644 .prettierignore create mode 100644 test/webpack/base.test.js create mode 100644 test/webpack/compile.js delete mode 100644 test/webpack/index.test.js create mode 100644 test/webpack/prod.test.js diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..5cc1873034 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +generated +__fixtures__ +dist \ No newline at end of file diff --git a/test/webpack/base.test.js b/test/webpack/base.test.js new file mode 100644 index 0000000000..d783c25bb6 --- /dev/null +++ b/test/webpack/base.test.js @@ -0,0 +1,29 @@ +import createDevConfig from '@lib/webpack/dev'; +import compile from './compile'; +import loadSetup from '../loadSetup'; + +describe('webpack dev config', () => { + const timeOut = 20000; // 20 seconds + + test( + 'simple', + async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }, + timeOut + ); + + test( + 'custom', + async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createDevConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }, + timeOut + ); +}); diff --git a/test/webpack/compile.js b/test/webpack/compile.js new file mode 100644 index 0000000000..8d2f2b9516 --- /dev/null +++ b/test/webpack/compile.js @@ -0,0 +1,12 @@ +import webpack from 'webpack'; + +export default function compile(config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err || stats.hasErrors()) { + reject(new Error(`Failed to compile with errors`)); + } + resolve('Compiled successfully'); + }); + }); +} diff --git a/test/webpack/index.test.js b/test/webpack/index.test.js deleted file mode 100644 index d86142588c..0000000000 --- a/test/webpack/index.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import webpack from 'webpack'; -import createDevConfig from '@lib/webpack/dev'; -import createProdConfig from '@lib/webpack/prod'; -import loadSetup from '../loadSetup'; - -// webpack compiler helper function -function compile(config) { - return new Promise((resolve, reject) => { - webpack(config, (err, stats) => { - if (err || stats.hasErrors()) { - reject(new Error(`Failed to compile with errors`)); - } - resolve('Compiled successfully'); - }); - }); -} - -describe('webpack', () => { - const timeOut = 10000; // 10 seconds - - test('dev simple', async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, timeOut); - - test('dev custom', async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, timeOut); - - test('prod simple', async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, timeOut); - - test('prod custom', async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, timeOut); -}); diff --git a/test/webpack/prod.test.js b/test/webpack/prod.test.js new file mode 100644 index 0000000000..04914b9953 --- /dev/null +++ b/test/webpack/prod.test.js @@ -0,0 +1,28 @@ +import createProdConfig from '@lib/webpack/prod'; +import compile from './compile'; +import loadSetup from '../loadSetup'; + +describe('webpack production config', () => { + const timeOut = 20000; // 20 seconds + test( + 'simple', + async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }, + timeOut + ); + + test( + 'custom', + async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createProdConfig(props).toConfig(); + return expect(compile(config)).resolves.toBe('Compiled successfully'); + }, + timeOut + ); +}); From d33343b7c6e197dd68b419133259e8589ec88136 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 16:25:29 +0800 Subject: [PATCH 081/135] feat: use ejs to build html template --- lib/core/prodEntry.js | 15 ++- lib/core/prodTemplate.ejs | 17 +++ lib/core/prodTemplate.js | 21 --- lib/webpack/prod.js | 14 +- package.json | 1 + yarn.lock | 272 +++----------------------------------- 6 files changed, 52 insertions(+), 288 deletions(-) create mode 100644 lib/core/prodTemplate.ejs delete mode 100644 lib/core/prodTemplate.js diff --git a/lib/core/prodEntry.js b/lib/core/prodEntry.js index 60fb5a99fa..24ff2ac532 100644 --- a/lib/core/prodEntry.js +++ b/lib/core/prodEntry.js @@ -4,7 +4,6 @@ import ReactDOM from 'react-dom'; import ReactDOMServer from 'react-dom/server'; import App from './App'; -import createHtml from './prodTemplate'; // Client side render (e.g: running in browser) to become single-page application (SPA) if (typeof document !== 'undefined') { @@ -24,11 +23,13 @@ export default function render(locals, callback) { ); - const html = createHtml({ - title: locals.title, - body, - bundlejs: locals.bundlejs, - lang: locals.lang - }); + + // Build HTML template + const assets = Object.keys(locals.webpackStats.compilation.assets); + const css = assets.filter(value => value.match(/\.css$/)); + const js = assets.filter(value => value.match(/\.js$/)); + const {title, baseUrl, lang = 'en', template} = locals; + const html = template({body, baseUrl, css, js, title, lang}); + callback(null, html); } diff --git a/lib/core/prodTemplate.ejs b/lib/core/prodTemplate.ejs new file mode 100644 index 0000000000..9c8cdbc09d --- /dev/null +++ b/lib/core/prodTemplate.ejs @@ -0,0 +1,17 @@ + + + + + + <%- title %> + <% css.forEach(function(file){ %> + + <% }); %> + + +
    <%- body %>
    + <% js.forEach(function(file){ %> + + <% }); %> + + \ No newline at end of file diff --git a/lib/core/prodTemplate.js b/lib/core/prodTemplate.js deleted file mode 100644 index 95f23d1bb5..0000000000 --- a/lib/core/prodTemplate.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Html - * This Html.js file acts as a template that we insert all our generated - * application code into before sending it to the client as regular HTML. - * Note we're returning a template string from this function. - */ - -module.exports = function createHtml({title, body, bundlejs, lang}) { - return ` - - - - ${title} - - -
    ${body}
    - - - - `; -}; diff --git a/lib/webpack/prod.js b/lib/webpack/prod.js index 7c402ae208..506be0d81f 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/prod.js @@ -1,4 +1,6 @@ const path = require('path'); +const fs = require('fs'); +const ejs = require('ejs'); const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); @@ -14,15 +16,21 @@ module.exports = function createProdConfig(props) { const {siteConfig, docsData, pagesData} = props; - // Find all available paths to be rendered + // static site generator webpack plugin const paths = [...docsData, ...pagesData].map(data => data.path); + const template = ejs.compile( + fs.readFileSync( + path.resolve(__dirname, '../core/prodTemplate.ejs'), + 'utf-8' + ) + ); config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', locals: { - bundlejs: 'bundle.js', title: siteConfig.title || 'Munseo', - lang: 'en' + baseUrl: siteConfig.baseUrl, + template }, paths } diff --git a/package.json b/package.json index 011398767d..bd61bc7a1f 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "chokidar": "^2.0.4", "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", + "ejs": "^2.6.1", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", diff --git a/yarn.lock b/yarn.lock index 81576d1c68..84b6abf339 100644 --- a/yarn.lock +++ b/yarn.lock @@ -234,7 +234,7 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -accepts@^1.3.5, accepts@~1.3.5: +accepts@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: @@ -263,7 +263,7 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: +acorn@^5.0.0, acorn@^5.5.0, acorn@^5.5.3, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -423,10 +423,6 @@ array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - array-includes@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" @@ -1137,14 +1133,6 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bfj-node4@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.3.1.tgz#e23d8b27057f1d0214fc561142ad9db998f26830" - dependencies: - bluebird "^3.5.1" - check-types "^7.3.0" - tryer "^1.0.0" - big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -1161,21 +1149,6 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" -body-parser@1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" - on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" - boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -1326,10 +1299,6 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - cacache@^10.0.4: version "10.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" @@ -1461,10 +1430,6 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" -check-types@^7.3.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" - cheerio@^0.22.0: version "0.22.0" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" @@ -1625,10 +1590,6 @@ commander@2.16.x, commander@^2.11.0, commander@^2.16.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" -commander@^2.13.0: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1700,11 +1661,11 @@ contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -content-disposition@0.5.2, content-disposition@~0.5.2: +content-disposition@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type@^1.0.4, content-type@~1.0.4: +content-type@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -1712,14 +1673,6 @@ convert-source-map@^1.4.0, convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - cookies@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" @@ -1885,7 +1838,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1990,10 +1943,6 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - depd@^1.1.2, depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2005,7 +1954,7 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@^1.0.4, destroy@~1.0.4: +destroy@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2158,7 +2107,7 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ejs@^2.5.7: +ejs@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" @@ -2186,10 +2135,6 @@ emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -2271,7 +2216,7 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.1: d "1" es5-ext "~0.10.14" -escape-html@^1.0.3, escape-html@~1.0.3: +escape-html@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2463,10 +2408,6 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - eval@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.2.tgz#9f7103284c105a66df4030b2b3273165837013da" @@ -2565,41 +2506,6 @@ expect@^23.4.0: jest-message-util "^23.4.0" jest-regex-util "^23.3.0" -express@^4.16.2: - version "4.16.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" - dependencies: - accepts "~1.3.5" - array-flatten "1.1.1" - body-parser "1.18.2" - content-disposition "0.5.2" - content-type "~1.0.4" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.1.1" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.2" - path-to-regexp "0.1.7" - proxy-addr "~2.0.3" - qs "6.5.1" - range-parser "~1.2.0" - safe-buffer "5.1.1" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" - utils-merge "1.0.1" - vary "~1.1.2" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -2731,10 +2637,6 @@ filesize@3.5.11: version "3.5.11" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.11.tgz#1919326749433bb3cf77368bd158caabcc19e9ee" -filesize@^3.5.11: - version "3.6.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -2754,18 +2656,6 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -finalhandler@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.4.0" - unpipe "~1.0.0" - find-cache-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" @@ -2829,17 +2719,13 @@ form-data@~2.3.1: combined-stream "1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: map-cache "^0.2.2" -fresh@0.5.2, fresh@~0.5.2: +fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -3063,13 +2949,6 @@ gzip-size@3.0.0: dependencies: duplexer "^0.1.1" -gzip-size@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-4.1.0.tgz#8ae096257eabe7d69c45be2b67c448124ffb517c" - dependencies: - duplexer "^0.1.1" - pify "^3.0.0" - handlebars@^4.0.3: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" @@ -3264,15 +3143,6 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.6.1" -http-errors@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - http-errors@^1.6.1, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -3397,10 +3267,6 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4590,10 +4456,6 @@ meow@^5.0.0: trim-newlines "^2.0.0" yargs-parser "^10.0.0" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - merge-options@^1.0.0, merge-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32" @@ -4614,10 +4476,6 @@ merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -4671,10 +4529,6 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.17, mime-types@~2.1.18: dependencies: mime-db "~1.35.0" -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - mime@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" @@ -5057,7 +4911,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -on-finished@^2.3.0, on-finished@~2.3.0: +on-finished@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: @@ -5079,10 +4933,6 @@ only@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" -opener@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - opn@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" @@ -5252,7 +5102,7 @@ parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" -parseurl@^1.3.2, parseurl@~1.3.2: +parseurl@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -5294,10 +5144,6 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" @@ -5468,13 +5314,6 @@ prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" -proxy-addr@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.8.0" - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -5524,10 +5363,6 @@ punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" -qs@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - qs@~6.5.1: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -5569,19 +5404,10 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.0.3, range-parser@~1.2.0: +range-parser@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" - unpipe "1.0.0" - rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -6028,10 +5854,6 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -safe-buffer@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -6086,37 +5908,10 @@ semver-diff@^2.0.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" -send@0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" - serialize-javascript@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" -serve-static@1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.2" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -6147,10 +5942,6 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -6364,14 +6155,10 @@ static-site-generator-webpack-plugin@^3.4.1: url "^0.11.0" webpack-sources "^0.2.0" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", statuses@^1.5.0: +"statuses@>= 1.4.0 < 2", statuses@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - std-env@^1.1.0, std-env@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/std-env/-/std-env-1.3.1.tgz#4e1758412439e9ece1d437b1b098551911aa44ee" @@ -6674,10 +6461,6 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tryer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" - tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -6702,7 +6485,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@^1.6.16, type-is@~1.6.15, type-is@~1.6.16: +type-is@^1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: @@ -6796,10 +6579,6 @@ universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -6903,10 +6682,6 @@ utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - uuid@^3.1.0: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -6926,7 +6701,7 @@ value-equal@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" -vary@^1.1.2, vary@~1.1.2: +vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -6987,23 +6762,6 @@ webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" -webpack-bundle-analyzer@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz#07d2176c6e86c3cdce4c23e56fae2a7b6b4ad526" - dependencies: - acorn "^5.3.0" - bfj-node4 "^5.2.0" - chalk "^2.3.0" - commander "^2.13.0" - ejs "^2.5.7" - express "^4.16.2" - filesize "^3.5.11" - gzip-size "^4.1.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - opener "^1.4.3" - ws "^4.0.0" - webpack-chain@^4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.8.0.tgz#06fc3dbb9f2707d4c9e899fc6250fbcf2afe6fd1" From ea706d2830384b898b4899c84e56a43f188865a2 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 11 Aug 2018 16:29:52 +0800 Subject: [PATCH 082/135] feat: hash the webpack-compiled js file --- docs/highlight.md | 31 +++++++++++++++++++++++++++++++ lib/webpack/base.js | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 docs/highlight.md diff --git a/docs/highlight.md b/docs/highlight.md new file mode 100644 index 0000000000..8fb83f8423 --- /dev/null +++ b/docs/highlight.md @@ -0,0 +1,31 @@ +--- +id: highlight +title: Syntax highlighting demo +--- + +```cpp +#include +using namespace std; + +int main() { + cout << "Hello world\n"; + return 0; +} + +``` + +```js +class Example extends React.Component { + render() { + return ( + + Docusaurus + ); @@ -67,17 +42,17 @@ class Board extends React.Component { render() { return (
    -
    +
    {this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)}
    -
    +
    {this.renderSquare(3)} {this.renderSquare(4)} {this.renderSquare(5)}
    -
    +
    {this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)} @@ -149,11 +124,11 @@ class Game extends React.Component { } return ( -
    -
    +
    +
    this.handleClick(i)} />
    -
    +
    {status}
      {moves}
    diff --git a/yarn.lock b/yarn.lock index 84b6abf339..e614af14c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1777,6 +1777,23 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +css-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.0.tgz#9f46aaa5ca41dbe31860e3b62b8e23c42916bf56" + dependencies: + babel-code-frame "^6.26.0" + css-selector-tokenizer "^0.7.0" + icss-utils "^2.1.0" + loader-utils "^1.0.2" + lodash.camelcase "^4.3.0" + postcss "^6.0.23" + postcss-modules-extract-imports "^1.2.0" + postcss-modules-local-by-default "^1.2.0" + postcss-modules-scope "^1.1.0" + postcss-modules-values "^1.3.0" + postcss-value-parser "^3.3.0" + source-list-map "^2.0.0" + css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -1786,10 +1803,22 @@ css-select@^1.1.0, css-select@~1.2.0: domutils "1.5.1" nth-check "~1.0.1" +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" @@ -2585,6 +2614,10 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + faye-websocket@~0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" @@ -3178,6 +3211,16 @@ iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: dependencies: safer-buffer ">= 2.1.2 < 3" +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + +icss-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" + dependencies: + postcss "^6.0.1" + ieee754@^1.1.11, ieee754@^1.1.4: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" @@ -4256,6 +4299,10 @@ lodash.bind@^4.1.4: version "4.2.1" resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -4537,6 +4584,14 @@ mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" +mini-css-extract-plugin@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.1.tgz#d2bcf77bb2596b8e4bd9257e43d3f9164c2e86cb" + dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + loader-utils "^1.1.0" + webpack-sources "^1.1.0" + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -5234,6 +5289,45 @@ posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" +postcss-modules-extract-imports@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + dependencies: + postcss "^6.0.1" + +postcss-modules-local-by-default@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-scope@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-values@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" + +postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss@^6.0.1, postcss@^6.0.23: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -5616,6 +5710,14 @@ regexpp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -6267,6 +6369,13 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +style-loader@^0.22.1: + version "0.22.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.22.1.tgz#901ea28aac78fcc00c5075585ac07d7ef3f87a52" + dependencies: + loader-utils "^1.1.0" + schema-utils "^0.4.5" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -6277,7 +6386,7 @@ supports-color@^3.1.2: dependencies: has-flag "^1.0.0" -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: From 3eb982310556ca3cd93c0f7246b6d10c75cf5239 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 12 Aug 2018 23:17:39 +0800 Subject: [PATCH 084/135] test: validate generated webpack config instead of compiling --- test/load/__snapshots__/routes.test.js.snap | 78 ++++++++++++++++++--- test/webpack/base.test.js | 42 +++++------ test/webpack/compile.js | 12 ---- test/webpack/dev.test.js | 21 ++++++ test/webpack/prod.test.js | 37 ++++------ 5 files changed, 121 insertions(+), 69 deletions(-) delete mode 100644 test/webpack/compile.js create mode 100644 test/webpack/dev.test.js diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap index 075ce45f36..d9e6869438 100644 --- a/test/load/__snapshots__/routes.test.js.snap +++ b/test/load/__snapshots__/routes.test.js.snap @@ -21,8 +21,37 @@ exports[`genRoutesConfig website with only docs 1`] = ` import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; - -const routes = [,, +import MDHello from '@docs/hello.md'; +import MDFooBar from '@docs/foo/bar.md'; +import MDFooBaz from '@docs/foo/baz.md'; +const routes = [ + { + path: \\"/hello\\", + exact: true, + component: (props) => ( + + + + ) + }, + { + path: \\"/foo/bar\\", + exact: true, + component: (props) => ( + + + + ) + }, + { + path: \\"/foo/baz\\", + exact: true, + component: (props) => ( + + + + ) + },, { path: '*', component: NotFound @@ -77,10 +106,39 @@ import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; import JSFoo from '@pages/foo.js'; import JSIndex from '@pages/index.js'; -import JSFooIndex from '@pages/foo/index.js'; import JSBarBaz from '@pages/bar/baz.js'; - -const routes = [, +import JSFooIndex from '@pages/foo/index.js'; +import MDHello from '@docs/hello.md'; +import MDFooBaz from '@docs/foo/baz.md'; +import MDFooBar from '@docs/foo/bar.md'; +const routes = [ + { + path: \\"/hello\\", + exact: true, + component: (props) => ( + + + + ) + }, + { + path: \\"/foo/baz\\", + exact: true, + component: (props) => ( + + + + ) + }, + { + path: \\"/foo/bar\\", + exact: true, + component: (props) => ( + + + + ) + }, { path: \\"/foo\\", exact: true, @@ -91,16 +149,16 @@ const routes = [, exact: true, component: JSIndex }, - { - path: \\"/foo/\\", - exact: true, - component: JSFooIndex - }, { path: \\"/bar/baz\\", exact: true, component: JSBarBaz }, + { + path: \\"/foo/\\", + exact: true, + component: JSFooIndex + }, { path: '*', component: NotFound diff --git a/test/webpack/base.test.js b/test/webpack/base.test.js index d783c25bb6..1e17156703 100644 --- a/test/webpack/base.test.js +++ b/test/webpack/base.test.js @@ -1,29 +1,21 @@ -import createDevConfig from '@lib/webpack/dev'; -import compile from './compile'; +import createBaseConfig from '@lib/webpack/base'; +import {validate} from 'webpack'; import loadSetup from '../loadSetup'; -describe('webpack dev config', () => { - const timeOut = 20000; // 20 seconds +describe('webpack base config', () => { + test('simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createBaseConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); - test( - 'simple', - async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, - timeOut - ); - - test( - 'custom', - async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createDevConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, - timeOut - ); + test('custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createBaseConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); }); diff --git a/test/webpack/compile.js b/test/webpack/compile.js deleted file mode 100644 index 8d2f2b9516..0000000000 --- a/test/webpack/compile.js +++ /dev/null @@ -1,12 +0,0 @@ -import webpack from 'webpack'; - -export default function compile(config) { - return new Promise((resolve, reject) => { - webpack(config, (err, stats) => { - if (err || stats.hasErrors()) { - reject(new Error(`Failed to compile with errors`)); - } - resolve('Compiled successfully'); - }); - }); -} diff --git a/test/webpack/dev.test.js b/test/webpack/dev.test.js new file mode 100644 index 0000000000..23397124de --- /dev/null +++ b/test/webpack/dev.test.js @@ -0,0 +1,21 @@ +import createDevConfig from '@lib/webpack/dev'; +import {validate} from 'webpack'; +import loadSetup from '../loadSetup'; + +describe('webpack dev config', () => { + test('simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createDevConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); + + test('custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createDevConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); +}); diff --git a/test/webpack/prod.test.js b/test/webpack/prod.test.js index 04914b9953..019d1a0404 100644 --- a/test/webpack/prod.test.js +++ b/test/webpack/prod.test.js @@ -1,28 +1,21 @@ import createProdConfig from '@lib/webpack/prod'; -import compile from './compile'; +import {validate} from 'webpack'; import loadSetup from '../loadSetup'; describe('webpack production config', () => { - const timeOut = 20000; // 20 seconds - test( - 'simple', - async () => { - console.log = jest.fn(); - const props = await loadSetup('simple'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, - timeOut - ); + test('simple', async () => { + console.log = jest.fn(); + const props = await loadSetup('simple'); + const config = createProdConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); - test( - 'custom', - async () => { - console.log = jest.fn(); - const props = await loadSetup('custom'); - const config = createProdConfig(props).toConfig(); - return expect(compile(config)).resolves.toBe('Compiled successfully'); - }, - timeOut - ); + test('custom', async () => { + console.log = jest.fn(); + const props = await loadSetup('custom'); + const config = createProdConfig(props).toConfig(); + const errors = validate(config); + expect(errors.length).toBe(0); + }); }); From bf1e30dc526cbae89bef413bb12f2b77bf77c61a Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 12 Aug 2018 23:17:56 +0800 Subject: [PATCH 085/135] dep: use forked version of static-generator-webpack-plugin --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 0382d8cc67..879cbcf08c 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "react-router-dom": "^4.3.1", "remarkable": "^1.7.1", "semver": "^5.5.0", - "static-site-generator-webpack-plugin": "^3.4.1", + "static-site-generator-webpack-plugin": "endiliey/static-site-generator-webpack-plugin#master", "style-loader": "^0.22.1", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", diff --git a/yarn.lock b/yarn.lock index e614af14c8..9d3f1bf739 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6247,9 +6247,9 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -static-site-generator-webpack-plugin@^3.4.1: +static-site-generator-webpack-plugin@endiliey/static-site-generator-webpack-plugin#master: version "3.4.1" - resolved "https://registry.yarnpkg.com/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-3.4.1.tgz#6ee22468830bc546798a37e0fca6fd699cc93b81" + resolved "https://codeload.github.com/endiliey/static-site-generator-webpack-plugin/tar.gz/d29365613d5489dabe8bae912d7541334e6acf1b" dependencies: bluebird "^3.0.5" cheerio "^0.22.0" From 406106b67e1ff37663254d0ce30f4e169e874149 Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 23 Aug 2018 21:46:14 +0800 Subject: [PATCH 086/135] feat: code split & use react helmet --- .eslintignore | 3 +- lib/commands/build.js | 14 ++++--- lib/commands/start.js | 16 +++++++- lib/core/clientEntry.js | 19 ++++++++++ lib/core/devEntry.js | 12 ------ lib/core/prerender.js | 18 +++++++++ lib/core/prodEntry.js | 35 ------------------ lib/core/prodTemplate.ejs | 17 --------- lib/core/serverEntry.js | 59 ++++++++++++++++++++++++++++++ lib/load/routes.js | 36 +++++++----------- lib/theme/Loading.js | 15 ++++++++ lib/webpack/base.js | 6 ++- lib/webpack/client.js | 20 ++++++++++ lib/webpack/dev.js | 24 ------------ lib/webpack/{prod.js => server.js} | 25 +++++-------- package.json | 8 +++- website/pages/index.js | 5 +-- website/pages/tictactoe.js | 2 + yarn.lock | 53 ++++++++++++++++++++++++--- 19 files changed, 241 insertions(+), 146 deletions(-) create mode 100644 lib/core/clientEntry.js delete mode 100644 lib/core/devEntry.js create mode 100644 lib/core/prerender.js delete mode 100644 lib/core/prodEntry.js delete mode 100644 lib/core/prodTemplate.ejs create mode 100644 lib/core/serverEntry.js create mode 100644 lib/theme/Loading.js create mode 100644 lib/webpack/client.js delete mode 100644 lib/webpack/dev.js rename lib/webpack/{prod.js => server.js} (59%) diff --git a/.eslintignore b/.eslintignore index 5cc1873034..890258d49f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ generated __fixtures__ -dist \ No newline at end of file +dist +website \ No newline at end of file diff --git a/lib/commands/build.js b/lib/commands/build.js index 7f017ca84e..cbb6501d7c 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -4,7 +4,8 @@ const chalk = require('chalk'); const fs = require('fs-extra'); const globby = require('globby'); const load = require('../load'); -const createProdConfig = require('../webpack/prod'); +const createServerConfig = require('../webpack/server'); +const createClientConfig = require('../webpack/client'); function compile(config) { return new Promise((resolve, reject) => { @@ -35,11 +36,14 @@ module.exports = async function build(siteDir, cliOptions = {}) { const props = await load(siteDir); - // create compiler from generated webpack config - const config = createProdConfig(props).toConfig(); + const serverConfig = createServerConfig(props).toConfig(); + const clientConfig = createClientConfig(props).toConfig(); - // compile! - await compile(config); + // we build the client bundles first + await compile(clientConfig); + + // then we build the server bundles (render the static HTML and pick client bundle) + await compile(serverConfig); // copy static files const {outDir} = props; diff --git a/lib/commands/start.js b/lib/commands/start.js index a42804ad2b..a8ee2f4f5f 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -10,8 +10,9 @@ const serveStatic = require('koa-static'); const history = require('connect-history-api-fallback'); const portfinder = require('portfinder'); const serve = require('webpack-serve'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../load'); -const createDevConfig = require('../webpack/dev'); +const createClientConfig = require('../webpack/client'); async function getPort(reqPort) { portfinder.basePort = parseInt(reqPort, 10) || 3000; @@ -52,7 +53,18 @@ module.exports = async function start(siteDir, cliOptions = {}) { const {baseUrl} = props; // create compiler from generated webpack config - const config = createDevConfig(props).toConfig(); + let config = createClientConfig(props); + + const {siteConfig} = props; + config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ + { + hash: true, + template: path.resolve(__dirname, '../core/devTemplate.ejs'), + filename: 'index.html', + title: siteConfig.title + } + ]); + config = config.toConfig(); const compiler = webpack(config); // webpack-serve diff --git a/lib/core/clientEntry.js b/lib/core/clientEntry.js new file mode 100644 index 0000000000..38f475e627 --- /dev/null +++ b/lib/core/clientEntry.js @@ -0,0 +1,19 @@ +import React from 'react'; +import {BrowserRouter} from 'react-router-dom'; +import ReactDOM from 'react-dom'; + +import App from './App'; +import prerender from './prerender'; +import routes from '@generated/routes'; // eslint-disable-line + +// Client side render (e.g: running in browser) to become single-page application (SPA) +if (typeof window !== 'undefined' && typeof document !== 'undefined') { + prerender(routes, window.location.pathname).then(() => { + ReactDOM.render( + + + , + document.getElementById('app') + ); + }); +} diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js deleted file mode 100644 index 3cfc7386bc..0000000000 --- a/lib/core/devEntry.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import {BrowserRouter} from 'react-router-dom'; - -import App from './App'; - -ReactDOM.render( - - - , - document.getElementById('app') -); diff --git a/lib/core/prerender.js b/lib/core/prerender.js new file mode 100644 index 0000000000..7e41893617 --- /dev/null +++ b/lib/core/prerender.js @@ -0,0 +1,18 @@ +import {matchRoutes} from 'react-router-config'; + +/** + * This helps us to make sure all the async component for that particular route + * is loaded before rendering. This is to avoid loading screens on first page load + */ +export default function prerender(routeConfig, providedLocation) { + const matches = matchRoutes(routeConfig, providedLocation); + return Promise.all( + matches.map(match => { + const {component} = match.route; + if (component && component.preload) { + return component.preload(); + } + return undefined; + }) + ); +} diff --git a/lib/core/prodEntry.js b/lib/core/prodEntry.js deleted file mode 100644 index 24ff2ac532..0000000000 --- a/lib/core/prodEntry.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import {BrowserRouter, StaticRouter} from 'react-router-dom'; -import ReactDOM from 'react-dom'; -import ReactDOMServer from 'react-dom/server'; - -import App from './App'; - -// Client side render (e.g: running in browser) to become single-page application (SPA) -if (typeof document !== 'undefined') { - ReactDOM.render( - - - , - document.getElementById('app') - ); -} - -// Renderer for static-site-generator-webpack-plugin (async rendering via callbacks) -export default function render(locals, callback) { - const context = {}; - const body = ReactDOMServer.renderToString( - - - - ); - - // Build HTML template - const assets = Object.keys(locals.webpackStats.compilation.assets); - const css = assets.filter(value => value.match(/\.css$/)); - const js = assets.filter(value => value.match(/\.js$/)); - const {title, baseUrl, lang = 'en', template} = locals; - const html = template({body, baseUrl, css, js, title, lang}); - - callback(null, html); -} diff --git a/lib/core/prodTemplate.ejs b/lib/core/prodTemplate.ejs deleted file mode 100644 index 2c11428a73..0000000000 --- a/lib/core/prodTemplate.ejs +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - <%- title %> - <% css.forEach(function(file){ %> - - <% }); %> - - -
    <%- body %>
    - <% js.forEach(function(file){ %> - - <% }); %> - - \ No newline at end of file diff --git a/lib/core/serverEntry.js b/lib/core/serverEntry.js new file mode 100644 index 0000000000..1bd7dab180 --- /dev/null +++ b/lib/core/serverEntry.js @@ -0,0 +1,59 @@ +import React from 'react'; +import {StaticRouter} from 'react-router-dom'; +import ReactDOMServer from 'react-dom/server'; +import Helmet from 'react-helmet'; + +import App from './App'; +import prerender from './prerender'; +import routes from '@generated/routes'; // eslint-disable-line +import webpackClientStats from '@build/client.stats.json'; //eslint-disable-line + +// Renderer for static-site-generator-webpack-plugin (async rendering via promises) +export default function render(locals) { + return prerender(routes, locals.path).then(() => { + const context = {}; + const appHtml = ReactDOMServer.renderToString( + + + + ); + + const helmet = Helmet.renderStatic(); + const htmlAttributes = helmet.htmlAttributes.toString(); + const bodyAttributes = helmet.bodyAttributes.toString(); + const metaStrings = [ + helmet.title.toString(), + helmet.meta.toString(), + helmet.link.toString() + ]; + const metaHtml = metaStrings.filter(Boolean).join('\n '); + + const assets = webpackClientStats.assetsByChunkName.main; + const jsFiles = assets.filter(value => value.match(/\.js$/)); + const cssFiles = assets.filter(value => value.match(/\.css$/)); + const {baseUrl} = locals; + + const html = ` + + + + ${metaHtml} + + + ${cssFiles.map( + cssFile => + `` + )} + + +
    ${appHtml}
    + ${jsFiles.map( + jsFile => + `` + )} + + +`; + return html; + }); +} diff --git a/lib/load/routes.js b/lib/load/routes.js index 2b6f48fd60..286ca42b76 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,40 +1,32 @@ -const {fileToComponentName} = require('./utils'); - async function genRoutesConfig({docsData = [], pagesData = []}) { function genDocsRoute({path: docsPath, source}) { - const componentName = fileToComponentName(source); return ` { path: ${JSON.stringify(docsPath)}, exact: true, - component: (props) => ( - - <${componentName} /> - - ) + component: Loadable({ + loader: () => import('@docs/${source}'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) }`; } - function genDocsImport({source}) { - const componentName = fileToComponentName(source); - return `import ${componentName} from '@docs/${source}';`; - } - function genPagesRoute({path: pagesPath, source}) { - const componentName = fileToComponentName(source); return ` { path: ${JSON.stringify(pagesPath)}, exact: true, - component: ${componentName} + component: Loadable({ + loader: () => import('@pages/${source}'), + loading: Loading + }) }`; } - function genPagesImport({source}) { - const componentName = fileToComponentName(source); - return `import ${componentName} from '@pages/${source}';`; - } - const notFoundRoute = `, { path: '*', @@ -43,10 +35,10 @@ async function genRoutesConfig({docsData = [], pagesData = []}) { return ( `import React from 'react';\n` + + `import Loading from '@theme/Loading';\n` + + `import Loadable from 'react-loadable';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + - `${pagesData.map(genPagesImport).join('\n')}\n` + - `${docsData.map(genDocsImport).join('\n')}\n` + `const routes = [${docsData.map(genDocsRoute).join(',')},${pagesData .map(genPagesRoute) .join(',')}${notFoundRoute}\n];\n` + diff --git a/lib/theme/Loading.js b/lib/theme/Loading.js new file mode 100644 index 0000000000..c4af8d5525 --- /dev/null +++ b/lib/theme/Loading.js @@ -0,0 +1,15 @@ +import React from 'react'; + +export default props => { + if (props.error) { + return ( +
    + Error!{' '} + +
    + ); + } + return
    Loading...
    ; +}; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index db3eec401e..2e3b496294 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -4,7 +4,7 @@ const path = require('path'); const mdLoader = require.resolve('./loader/markdown'); -module.exports = function createBaseConfig(props) { +module.exports = function createBaseConfig(props, isServer) { const { siteConfig, outDir, @@ -34,6 +34,7 @@ module.exports = function createBaseConfig(props) { .set('@site', siteDir) .set('@docs', docsDir) .set('@pages', pagesDir) + .set('@build', outDir) .set('@generated', path.resolve(__dirname, '../core/generated')) .set('@core', path.resolve(__dirname, '../core')) .end(); @@ -44,7 +45,8 @@ module.exports = function createBaseConfig(props) { .loader('babel-loader') .options({ babelrc: false, - presets: ['env', 'react'] + presets: ['env', 'react'], + plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import'] }); } diff --git a/lib/webpack/client.js b/lib/webpack/client.js new file mode 100644 index 0000000000..b7f21758be --- /dev/null +++ b/lib/webpack/client.js @@ -0,0 +1,20 @@ +const path = require('path'); +const webpackNiceLog = require('webpack-nicelog'); +const {StatsWriterPlugin} = require('webpack-stats-plugin'); +const createBaseConfig = require('./base'); + +module.exports = function createClientConfig(props) { + const config = createBaseConfig(props); + + config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js')); + + // write webpack stats object to a file so we can + // programmatically refer to the correct bundle path in Node.js server. + config + .plugin('stats') + .use(StatsWriterPlugin, [{filename: 'client.stats.json'}]); + + config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]); + + return config; +}; diff --git a/lib/webpack/dev.js b/lib/webpack/dev.js deleted file mode 100644 index dcdc3a6e51..0000000000 --- a/lib/webpack/dev.js +++ /dev/null @@ -1,24 +0,0 @@ -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const webpackNiceLog = require('webpack-nicelog'); -const createBaseConfig = require('./base'); - -module.exports = function createDevConfig(props) { - const config = createBaseConfig(props); - - config.entry('main').add(path.resolve(__dirname, '../core/devEntry.js')); - - const {siteConfig} = props; - config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ - { - inject: false, - hash: true, - template: path.resolve(__dirname, '../core/devTemplate.ejs'), - filename: 'index.html', - title: siteConfig.title - } - ]); - config.plugin('niceLog').use(webpackNiceLog, [{name: 'Development'}]); - - return config; -}; diff --git a/lib/webpack/prod.js b/lib/webpack/server.js similarity index 59% rename from lib/webpack/prod.js rename to lib/webpack/server.js index 506be0d81f..a562199727 100644 --- a/lib/webpack/prod.js +++ b/lib/webpack/server.js @@ -1,15 +1,16 @@ const path = require('path'); -const fs = require('fs'); -const ejs = require('ejs'); const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); module.exports = function createProdConfig(props) { - const config = createBaseConfig(props); + const config = createBaseConfig(props, true); - config.entry('main').add(path.resolve(__dirname, '../core/prodEntry.js')); - config.output.libraryTarget('umd'); + config.entry('main').add(path.resolve(__dirname, '../core/serverEntry.js')); + + config.target('node'); + + config.output.filename('server.bundle.js').libraryTarget('commonjs2'); // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) config.output.globalObject('this'); @@ -18,25 +19,19 @@ module.exports = function createProdConfig(props) { // static site generator webpack plugin const paths = [...docsData, ...pagesData].map(data => data.path); - const template = ejs.compile( - fs.readFileSync( - path.resolve(__dirname, '../core/prodTemplate.ejs'), - 'utf-8' - ) - ); config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', locals: { - title: siteConfig.title || 'Munseo', - baseUrl: siteConfig.baseUrl, - template + baseUrl: siteConfig.baseUrl }, paths } ]); // show compilation progress bar and build time - config.plugin('niceLog').use(webpackNiceLog, [{name: 'Production'}]); + config + .plugin('niceLog') + .use(webpackNiceLog, [{name: 'Server', color: 'yellow'}]); return config; }; diff --git a/package.json b/package.json index 879cbcf08c..6b2a272a39 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,8 @@ "dependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", + "babel-plugin-dynamic-import-node": "^2.0.0", + "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-preset-env": "^1.7.0", "babel-preset-react": "^6.24.1", "chalk": "^2.4.1", @@ -49,7 +51,6 @@ "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", "css-loader": "^1.0.0", - "ejs": "^2.6.1", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", @@ -65,6 +66,8 @@ "prismjs": "^1.15.0", "react": "^16.4.1", "react-dom": "^16.4.1", + "react-helmet": "^5.2.0", + "react-loadable": "^5.5.0", "react-router-config": "^1.0.0-beta.4", "react-router-dom": "^4.3.1", "remarkable": "^1.7.1", @@ -74,7 +77,8 @@ "webpack": "^4.16.3", "webpack-chain": "^4.8.0", "webpack-nicelog": "^2.2.1", - "webpack-serve": "^2.0.2" + "webpack-serve": "^2.0.2", + "webpack-stats-plugin": "^0.2.1" }, "engines": { "node": ">=8" diff --git a/website/pages/index.js b/website/pages/index.js index 2d89400073..5dd3022176 100644 --- a/website/pages/index.js +++ b/website/pages/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import TicTacToe from './tictactoe'; +import Helmet from 'react-helmet'; import {Link} from 'react-router-dom'; export default class Home extends React.Component { @@ -12,10 +12,9 @@ export default class Home extends React.Component { )); return (
    +

    Available Urls

      {routeLinks}
    -

    Play some TicTacToe

    -
    ); } diff --git a/website/pages/tictactoe.js b/website/pages/tictactoe.js index b102b7d1fe..e9c93dd8a2 100644 --- a/website/pages/tictactoe.js +++ b/website/pages/tictactoe.js @@ -1,4 +1,5 @@ import React from 'react'; +import Helmet from 'react-helmet'; import style from './tictactoe.css'; function Square(props) { @@ -125,6 +126,7 @@ class Game extends React.Component { return (
    +
    this.handleClick(i)} />
    diff --git a/yarn.lock b/yarn.lock index 9d3f1bf739..5492a2cc91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -723,6 +723,13 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.0.0.tgz#d6fc3f6c5e3bdc34e49c15faca7ce069755c0a57" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + object.assign "^4.1.0" + babel-plugin-istanbul@^4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" @@ -740,6 +747,10 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -1900,7 +1911,7 @@ decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" -deep-equal@~1.0.1: +deep-equal@^1.0.1, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -2136,10 +2147,6 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ejs@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" - electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" @@ -2490,6 +2497,10 @@ execa@^0.8.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exenv@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -5401,7 +5412,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: +prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -5547,6 +5558,21 @@ react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" +react-helmet@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7" + dependencies: + deep-equal "^1.0.1" + object-assign "^4.1.1" + prop-types "^15.5.4" + react-side-effect "^1.1.0" + +react-loadable@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4" + dependencies: + prop-types "^15.5.0" + react-router-config@^1.0.0-beta.4: version "1.0.0-beta.4" resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-1.0.0-beta.4.tgz#d202496dd0eabdf06cf24eb0793031f6891eef01" @@ -5574,6 +5600,13 @@ react-router@^4.3.1: prop-types "^15.6.1" warning "^4.0.1" +react-side-effect@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d" + dependencies: + exenv "^1.2.1" + shallowequal "^1.0.1" + react@^16.4.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32" @@ -6055,6 +6088,10 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallowequal@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -6970,6 +7007,10 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" +webpack-stats-plugin@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/webpack-stats-plugin/-/webpack-stats-plugin-0.2.1.tgz#1f5bac13fc25d62cbb5fd0ff646757dc802b8595" + webpack@^4.16.3: version "4.16.3" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525" From e13e1bffb4b7928d9f8d6dfd132ef0c25d1224e8 Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 23 Aug 2018 23:07:24 +0800 Subject: [PATCH 087/135] feat: remove/clean your build folder(s) before building --- lib/webpack/client.js | 6 ++++++ package.json | 1 + yarn.lock | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/lib/webpack/client.js b/lib/webpack/client.js index b7f21758be..af01ba309c 100644 --- a/lib/webpack/client.js +++ b/lib/webpack/client.js @@ -1,6 +1,7 @@ const path = require('path'); const webpackNiceLog = require('webpack-nicelog'); const {StatsWriterPlugin} = require('webpack-stats-plugin'); +const cleanWebpackPlugin = require('clean-webpack-plugin'); const createBaseConfig = require('./base'); module.exports = function createClientConfig(props) { @@ -8,6 +9,11 @@ module.exports = function createClientConfig(props) { config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js')); + const {outDir} = props; + config + .plugin('clean') + .use(cleanWebpackPlugin, [outDir, {verbose: false, allowExternal: true}]); + // write webpack stats object to a file so we can // programmatically refer to the correct bundle path in Node.js server. config diff --git a/package.json b/package.json index 6b2a272a39..336ebae2a8 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "babel-preset-react": "^6.24.1", "chalk": "^2.4.1", "chokidar": "^2.0.4", + "clean-webpack-plugin": "^0.1.19", "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", "css-loader": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 5492a2cc91..e98375889c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1521,6 +1521,12 @@ clean-css@4.1.x: dependencies: source-map "0.5.x" +clean-webpack-plugin@^0.1.19: + version "0.1.19" + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-0.1.19.tgz#ceda8bb96b00fe168e9b080272960d20fdcadd6d" + dependencies: + rimraf "^2.6.1" + cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" From 1f2c8a39a914ac90bcdbd39f718c6697d313209b Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 23 Aug 2018 23:36:39 +0800 Subject: [PATCH 088/135] chore: nits --- lib/commands/start.js | 1 + lib/load/routes.js | 2 +- lib/webpack/client.js | 7 +++---- lib/webpack/server.js | 5 ++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/commands/start.js b/lib/commands/start.js index a8ee2f4f5f..9550eab7c1 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -58,6 +58,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { const {siteConfig} = props; config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [ { + inject: false, hash: true, template: path.resolve(__dirname, '../core/devTemplate.ejs'), filename: 'index.html', diff --git a/lib/load/routes.js b/lib/load/routes.js index 286ca42b76..282446327a 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -35,8 +35,8 @@ async function genRoutesConfig({docsData = [], pagesData = []}) { return ( `import React from 'react';\n` + - `import Loading from '@theme/Loading';\n` + `import Loadable from 'react-loadable';\n` + + `import Loading from '@theme/Loading';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + `const routes = [${docsData.map(genDocsRoute).join(',')},${pagesData diff --git a/lib/webpack/client.js b/lib/webpack/client.js index af01ba309c..8c438ebc71 100644 --- a/lib/webpack/client.js +++ b/lib/webpack/client.js @@ -6,21 +6,20 @@ const createBaseConfig = require('./base'); module.exports = function createClientConfig(props) { const config = createBaseConfig(props); - config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js')); + // remove/clean build folders before building bundles const {outDir} = props; config .plugin('clean') .use(cleanWebpackPlugin, [outDir, {verbose: false, allowExternal: true}]); - // write webpack stats object to a file so we can - // programmatically refer to the correct bundle path in Node.js server. + // write webpack stats object so we can pickup correct client bundle path in server. config .plugin('stats') .use(StatsWriterPlugin, [{filename: 'client.stats.json'}]); + // show compilation progress bar and build time config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]); - return config; }; diff --git a/lib/webpack/server.js b/lib/webpack/server.js index a562199727..33b6fe0c29 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -3,13 +3,11 @@ const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); -module.exports = function createProdConfig(props) { +module.exports = function createServerConfig(props) { const config = createBaseConfig(props, true); config.entry('main').add(path.resolve(__dirname, '../core/serverEntry.js')); - config.target('node'); - config.output.filename('server.bundle.js').libraryTarget('commonjs2'); // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) @@ -28,6 +26,7 @@ module.exports = function createProdConfig(props) { paths } ]); + // show compilation progress bar and build time config .plugin('niceLog') From 23a85d907443f40560fef93078c425887e059adb Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 24 Aug 2018 00:05:37 +0800 Subject: [PATCH 089/135] fix: hot reload port should not be hardcoded in case it is used --- lib/commands/start.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/commands/start.js b/lib/commands/start.js index 9550eab7c1..5b7a96e831 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -50,6 +50,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { } const port = await getPort(cliOptions.port); + const hotPort = await getPort(port + 1); const {baseUrl} = props; // create compiler from generated webpack config @@ -79,7 +80,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { logLevel: 'silent' }, hotClient: { - port: port + 1, + port: hotPort, logLevel: 'error' }, logLevel: 'error', From 99cc83e88c3c7e6577753279eaa71be2ddb3ab21 Mon Sep 17 00:00:00 2001 From: Endilie Yacop Sucipto Date: Fri, 24 Aug 2018 10:29:44 +0800 Subject: [PATCH 090/135] chore: update readme --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index c34e1df0a0..88425d6b7d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,4 @@ # Munseo -📝⚡️ Transform your document (문서) to a website - -# Disclaimer: -This is still a *WORK IN PROGRESS*. Expect lot of bugs :) - -# Quick Start ## Development Server @@ -16,4 +10,4 @@ yarn start # open http://localhost:3000/ ```bash yarn build # check website/build -``` \ No newline at end of file +``` From d3e12c9455d94832ed53186dc31d858ac4e3dfea Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 26 Aug 2018 03:10:50 +0800 Subject: [PATCH 091/135] chore: update docs examples --- docs/foo/bar.md | 21 +- docs/foo/baz.md | 7 +- docs/highlight.md | 37 ++- website/static/css/todo.css | 378 ++++++++++++++++++++++++++ website/static/img/minion.png | Bin 93508 -> 0 bytes website/static/img/stormtroopocat.jpg | Bin 95977 -> 0 bytes yarn.lock | 4 + 7 files changed, 412 insertions(+), 35 deletions(-) create mode 100644 website/static/css/todo.css delete mode 100644 website/static/img/minion.png delete mode 100644 website/static/img/stormtroopocat.jpg diff --git a/docs/foo/bar.md b/docs/foo/bar.md index 9f978009c5..f50858ac64 100644 --- a/docs/foo/bar.md +++ b/docs/foo/bar.md @@ -1,6 +1,6 @@ --- id: bar -title: Bar +title: My Title --- # Remarkable @@ -21,6 +21,8 @@ Click the `clear` link to start with a clean slate, or get the `permalink` to sh ## Horizontal Rules +This is horizontal rule + ___ *** @@ -28,23 +30,6 @@ ___ *** -## Typographic replacements - -Enable typographer option to see result. - -(c) (C) (r) (R) (tm) (TM) (p) (P) +- - -test.. test... test..... test?..... test!.... - -!!!!!! ???? ,, - -Remarkable -- awesome - -"Smartypants, double quotes" - -'Smartypants, single quotes' - - ## Emphasis **This is bold text** diff --git a/docs/foo/baz.md b/docs/foo/baz.md index add729c51d..b8fc124222 100644 --- a/docs/foo/baz.md +++ b/docs/foo/baz.md @@ -1,12 +1,11 @@ --- id: baz -title: baz +title: Test Markdown --- ## Images -![Minion](/img/minion.png) -![Stormtroopocat](/img/stormtroopocat.jpg) +![Sakura](/img/sakura.png) Like links, Images also have a footnote style syntax @@ -14,8 +13,6 @@ Like links, Images also have a footnote style syntax With a reference later in the document defining the URL location: -[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" - ## Links [link text](http://dev.nodeca.com) diff --git a/docs/highlight.md b/docs/highlight.md index 8fb83f8423..371afed03a 100644 --- a/docs/highlight.md +++ b/docs/highlight.md @@ -14,18 +14,31 @@ int main() { ``` -```js -class Example extends React.Component { - render() { - return ( - - Docusaurus - + + ); + }); + + let status; + if (winner) { + status = 'Winner: ' + winner; + } else { + status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); + } + + return ( +
    +
    + this.handleClick(i)} /> +
    +
    +
    {status}
    +
      {moves}
    +
    +
    + ); + } +} + +export default Game; diff --git a/website/components/Tictactoe/square.js b/website/components/Tictactoe/square.js new file mode 100644 index 0000000000..1fed93a270 --- /dev/null +++ b/website/components/Tictactoe/square.js @@ -0,0 +1,10 @@ +import React from 'react'; +import styles from './styles.css'; + +export default props => { + return ( + + ); +}; diff --git a/website/pages/tictactoe.css b/website/components/Tictactoe/styles.css similarity index 81% rename from website/pages/tictactoe.css rename to website/components/Tictactoe/styles.css index 4a1a102c6e..5d5a305eba 100644 --- a/website/pages/tictactoe.css +++ b/website/components/Tictactoe/styles.css @@ -30,6 +30,9 @@ .game { display: flex; flex-direction: row; + margin-left: auto; + margin-right: auto; + justify-content: center; } .gameInfo { diff --git a/website/components/Todo/TodoItem.js b/website/components/Todo/TodoItem.js new file mode 100644 index 0000000000..a6a68879d5 --- /dev/null +++ b/website/components/Todo/TodoItem.js @@ -0,0 +1,94 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import classNames from 'classnames'; + +const ESCAPE_KEY = 27; +const ENTER_KEY = 13; + +export default class TodoItem extends React.Component { + constructor(props) { + super(props); + this.state = { + editText: props.todo.title + }; + this.handleEdit = this.handleEdit.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleChange = this.handleChange.bind(this); + } + + shouldComponentUpdate(nextProps, nextState) { + return ( + nextProps.todo !== this.props.todo || + nextProps.editing !== this.props.editing || + nextState.editText !== this.state.editText + ); + } + + componentDidUpdate(prevProps) { + if (!prevProps.editing && this.props.editing) { + const node = ReactDOM.findDOMNode(this.refs.editField); + node.focus(); + node.setSelectionRange(node.value.length, node.value.length); + } + } + + handleSubmit() { + const val = this.state.editText.trim(); + if (val) { + this.props.onSave(val); + this.setState({editText: val}); + } else { + this.props.onDestroy(); + } + } + + handleEdit() { + this.props.onEdit(); + this.setState({editText: this.props.todo.title}); + } + + handleKeyDown(event) { + if (event.which === ESCAPE_KEY) { + this.setState({editText: this.props.todo.title}); + this.props.onCancel(event); + } else if (event.which === ENTER_KEY) { + this.handleSubmit(event); + } + } + + handleChange(event) { + if (this.props.editing) { + this.setState({editText: event.target.value}); + } + } + + render() { + return ( +
  • +
    + + +
    + +
  • + ); + } +} diff --git a/website/components/Todo/TodoList.js b/website/components/Todo/TodoList.js new file mode 100644 index 0000000000..070a815c16 --- /dev/null +++ b/website/components/Todo/TodoList.js @@ -0,0 +1,29 @@ +import React from 'react'; +import TodoItem from './TodoItem'; + +export default function TodoList(props) { + const todoItems = props.todos.map(todo => ( + { + props.onToggle(todo); + }} + onDestroy={() => { + props.onDestroy(todo); + }} + onEdit={() => { + props.onEdit(todo); + }} + editing={props.editing(todo)} + onSave={text => { + props.onSave(todo, text); + }} + onCancel={() => { + props.onCancel(); + }} + /> + )); + + return
    {todoItems}
    ; +} diff --git a/website/components/Todo/index.js b/website/components/Todo/index.js new file mode 100644 index 0000000000..ec158d4a28 --- /dev/null +++ b/website/components/Todo/index.js @@ -0,0 +1,209 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import TodoList from './TodoList'; + +const ENTER_KEY = 13; + +function uuid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`; +} + +const todos = [ + { + id: 'ed0bcc48-bbbe-5f06-c7c9-2ccb0456ceba', + title: 'Build this Todo App.', + completed: true + }, + { + id: '42582304-3c6e-311e-7f88-7e3791caf88c', + title: '?????', + completed: true + }, + { + id: '1cf63885-5f75-8deb-19dc-9b6765deae6c', + title: '1,000 stars on GitHub.', + completed: false + }, + { + id: '63a871b2-0b6f-4427-9c35-304bc680a4b7', + title: 'Write a popular medium post.', + completed: false + }, + { + id: '63a871b2-0b6f-4422-9c35-304bc680a4b7', + title: 'Earn money through open source work.', + completed: false + }, + { + id: '036af7f9-1181-fb8f-258f-3f06034c020f', + title: 'Write a blog post.', + completed: false + } +]; + +class TodoApp extends React.Component { + constructor(props) { + super(props); + + this.state = { + editing: null, + newTodo: '', + todos: todos + }; + } + + handleChange(event) { + this.setState({newTodo: event.target.value}); + } + + handleNewTodoKeyDown(event) { + if (event.keyCode !== ENTER_KEY) { + return; + } + + event.preventDefault(); + + const val = this.state.newTodo.trim(); + + if (val) { + this.setState({ + todos: this.state.todos.concat({ + id: uuid(), + title: val, + completed: false + }), + newTodo: '' + }); + } + } + + toggleAll(event) { + const {checked} = event.target; + this.setState({ + todos: this.state.todos.map(todo => + Object.assign({}, todo, {completed: checked}) + ) + }); + } + + toggle(todoToToggle) { + this.setState({ + todos: this.state.todos.map(todo => { + if (todo === todoToToggle) { + return Object.assign({}, todo, { + completed: !todo.completed + }); + } + return todo; + }) + }); + } + + destroy(passedTodo) { + this.setState({ + todos: this.state.todos.filter(todo => todo !== passedTodo) + }); + } + + edit(todo) { + this.setState({editing: todo.id}); + } + + save(todoToSave, text) { + this.setState({ + todos: this.state.todos.map(todo => { + if (todo === todoToSave) { + return Object.assign({}, todo, { + title: text + }); + } + return todo; + }), + editing: null + }); + } + + cancel() { + this.setState({editing: null}); + } + + clearCompleted() { + this.setState({ + todos: this.state.todos.filter(todo => !todo.completed) + }); + } + + render() { + let main; + const {todos} = this.state; + + const activeTodoCount = todos.reduce( + (accum, todo) => (todo.completed ? accum : accum + 1), + 0 + ); + + if (todos.length) { + main = ( +
    + +
      + { + this.toggle(todo); + }} + onDestroy={todo => { + this.destroy(todo); + }} + onEdit={todo => { + this.edit(todo); + }} + editing={todo => this.state.editing === todo.id} + onSave={(todo, text) => { + this.save(todo, text); + }} + onCancel={() => this.cancel()} + /> +
    +
    + ); + } + + return ( +
    + + Todo App + + +
    +

    todos

    + { + this.handleNewTodoKeyDown(event); + }} + onChange={event => { + this.handleChange(event); + }} + autoFocus + /> +
    + {main} +
    + ); + } +} + +export default TodoApp; diff --git a/website/pages/index.js b/website/pages/index.js index 5dd3022176..4b7db8f1e5 100644 --- a/website/pages/index.js +++ b/website/pages/index.js @@ -1,21 +1,17 @@ import React from 'react'; import Helmet from 'react-helmet'; -import {Link} from 'react-router-dom'; +import Layout from '@theme/Layout'; +import Todo from '@site/components/Todo'; export default class Home extends React.Component { render() { - const {pagesData, docsData} = this.props; - const routeLinks = [...pagesData, ...docsData].map(data => ( -
  • - {data.path} -
  • - )); return ( -
    - -

    Available Urls

    -
      {routeLinks}
    -
    + + + Homepage + + + ); } } diff --git a/website/pages/tictactoe.js b/website/pages/tictactoe.js index e9c93dd8a2..41072c4387 100644 --- a/website/pages/tictactoe.js +++ b/website/pages/tictactoe.js @@ -1,142 +1,17 @@ -import React from 'react'; -import Helmet from 'react-helmet'; -import style from './tictactoe.css'; - -function Square(props) { - return ( - - ); -} - -function calculateWinner(squares) { - const lines = [ - [0, 1, 2], - [3, 4, 5], - [6, 7, 8], - [0, 3, 6], - [1, 4, 7], - [2, 5, 8], - [0, 4, 8], - [2, 4, 6] - ]; - for (let i = 0; i < lines.length; i++) { - const [a, b, c] = lines[i]; - if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { - return squares[a]; - } - } - return null; -} - -class Board extends React.Component { - renderSquare(i) { - return ( - this.props.onClick(i)} - /> - ); - } - - render() { - return ( -
    -
    - {this.renderSquare(0)} - {this.renderSquare(1)} - {this.renderSquare(2)} -
    -
    - {this.renderSquare(3)} - {this.renderSquare(4)} - {this.renderSquare(5)} -
    -
    - {this.renderSquare(6)} - {this.renderSquare(7)} - {this.renderSquare(8)} -
    -
    - ); - } -} - -class Game extends React.Component { - constructor(props) { - super(props); - this.state = { - history: [ - { - squares: Array(9).fill(null) - } - ], - stepNumber: 0, - xIsNext: true - }; - } - - handleClick(i) { - const history = this.state.history.slice(0, this.state.stepNumber + 1); - const current = history[history.length - 1]; - const squares = current.squares.slice(); - if (calculateWinner(squares) || squares[i]) { - return; - } - squares[i] = this.state.xIsNext ? 'X' : 'O'; - this.setState({ - history: history.concat([ - { - squares: squares - } - ]), - stepNumber: history.length, - xIsNext: !this.state.xIsNext - }); - } - - jumpTo(step) { - this.setState({ - stepNumber: step, - xIsNext: step % 2 === 0 - }); - } - - render() { - const history = this.state.history; - const current = history[this.state.stepNumber]; - const winner = calculateWinner(current.squares); - - const moves = history.map((step, move) => { - const desc = move ? 'Go to move #' + move : 'Go to game start'; - return ( -
  • - -
  • - ); - }); - - let status; - if (winner) { - status = 'Winner: ' + winner; - } else { - status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); - } - - return ( -
    - -
    - this.handleClick(i)} /> -
    -
    -
    {status}
    -
      {moves}
    -
    -
    - ); - } -} - -export default Game; +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; +import Tictactoe from '@site/components/Tictactoe'; + +export default class Home extends React.Component { + render() { + return ( + + + Tic Tac Toe + + + + ); + } +} From 3530cbe173551db15aeedf5193e9769fa09167c0 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 26 Aug 2018 03:15:25 +0800 Subject: [PATCH 093/135] test: update test webpack --- test/load/__snapshots__/routes.test.js.snap | 152 +++++++++++------- test/webpack/{dev.test.js => client.test.js} | 6 +- test/webpack/{prod.test.js => server.test.js} | 6 +- 3 files changed, 98 insertions(+), 66 deletions(-) rename test/webpack/{dev.test.js => client.test.js} (74%) rename test/webpack/{prod.test.js => server.test.js} (74%) diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap index d9e6869438..f03e3e2ec6 100644 --- a/test/load/__snapshots__/routes.test.js.snap +++ b/test/load/__snapshots__/routes.test.js.snap @@ -2,10 +2,10 @@ exports[`genRoutesConfig website with no docs/pages 1`] = ` "import React from 'react'; +import Loadable from 'react-loadable'; +import Loading from '@theme/Loading'; import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; - - const routes = [,, { path: '*', @@ -18,39 +18,46 @@ export default routes; exports[`genRoutesConfig website with only docs 1`] = ` "import React from 'react'; +import Loadable from 'react-loadable'; +import Loading from '@theme/Loading'; import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; - -import MDHello from '@docs/hello.md'; -import MDFooBar from '@docs/foo/bar.md'; -import MDFooBaz from '@docs/foo/baz.md'; const routes = [ { path: \\"/hello\\", exact: true, - component: (props) => ( - - - - ) + component: Loadable({ + loader: () => import('@docs/hello.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) }, { path: \\"/foo/bar\\", exact: true, - component: (props) => ( - - - - ) + component: Loadable({ + loader: () => import('@docs/foo/bar.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) }, { path: \\"/foo/baz\\", exact: true, - component: (props) => ( - - - - ) + component: Loadable({ + loader: () => import('@docs/foo/baz.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) },, { path: '*', @@ -63,33 +70,42 @@ export default routes; exports[`genRoutesConfig website with only pages 1`] = ` "import React from 'react'; +import Loadable from 'react-loadable'; +import Loading from '@theme/Loading'; import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; -import JSFoo from '@pages/foo.js'; -import JSIndex from '@pages/index.js'; -import JSBarBaz from '@pages/bar/baz.js'; -import JSFooIndex from '@pages/foo/index.js'; - const routes = [, { path: \\"/foo\\", exact: true, - component: JSFoo + component: Loadable({ + loader: () => import('@pages/foo.js'), + loading: Loading + }) }, { path: \\"/\\", exact: true, - component: JSIndex + component: Loadable({ + loader: () => import('@pages/index.js'), + loading: Loading + }) }, { path: \\"/bar/baz\\", exact: true, - component: JSBarBaz + component: Loadable({ + loader: () => import('@pages/bar/baz.js'), + loading: Loading + }) }, { path: \\"/foo/\\", exact: true, - component: JSFooIndex + component: Loadable({ + loader: () => import('@pages/foo/index.js'), + loading: Loading + }) }, { path: '*', @@ -102,62 +118,78 @@ export default routes; exports[`genRoutesConfig website with pages and docs 1`] = ` "import React from 'react'; +import Loadable from 'react-loadable'; +import Loading from '@theme/Loading'; import Docs from '@theme/Docs'; import NotFound from '@theme/NotFound'; -import JSFoo from '@pages/foo.js'; -import JSIndex from '@pages/index.js'; -import JSBarBaz from '@pages/bar/baz.js'; -import JSFooIndex from '@pages/foo/index.js'; -import MDHello from '@docs/hello.md'; -import MDFooBaz from '@docs/foo/baz.md'; -import MDFooBar from '@docs/foo/bar.md'; const routes = [ { path: \\"/hello\\", exact: true, - component: (props) => ( - - - - ) - }, - { - path: \\"/foo/baz\\", - exact: true, - component: (props) => ( - - - - ) + component: Loadable({ + loader: () => import('@docs/hello.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) }, { path: \\"/foo/bar\\", exact: true, - component: (props) => ( - - - - ) + component: Loadable({ + loader: () => import('@docs/foo/bar.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) + }, + { + path: \\"/foo/baz\\", + exact: true, + component: Loadable({ + loader: () => import('@docs/foo/baz.md'), + loading: Loading, + render(loaded, props) { + let Content = loaded.default; + return ; + } + }) }, { path: \\"/foo\\", exact: true, - component: JSFoo + component: Loadable({ + loader: () => import('@pages/foo.js'), + loading: Loading + }) }, { path: \\"/\\", exact: true, - component: JSIndex + component: Loadable({ + loader: () => import('@pages/index.js'), + loading: Loading + }) }, { path: \\"/bar/baz\\", exact: true, - component: JSBarBaz + component: Loadable({ + loader: () => import('@pages/bar/baz.js'), + loading: Loading + }) }, { path: \\"/foo/\\", exact: true, - component: JSFooIndex + component: Loadable({ + loader: () => import('@pages/foo/index.js'), + loading: Loading + }) }, { path: '*', diff --git a/test/webpack/dev.test.js b/test/webpack/client.test.js similarity index 74% rename from test/webpack/dev.test.js rename to test/webpack/client.test.js index 23397124de..2f22a3ffd0 100644 --- a/test/webpack/dev.test.js +++ b/test/webpack/client.test.js @@ -1,4 +1,4 @@ -import createDevConfig from '@lib/webpack/dev'; +import createClientConfig from '@lib/webpack/client'; import {validate} from 'webpack'; import loadSetup from '../loadSetup'; @@ -6,7 +6,7 @@ describe('webpack dev config', () => { test('simple', async () => { console.log = jest.fn(); const props = await loadSetup('simple'); - const config = createDevConfig(props).toConfig(); + const config = createClientConfig(props).toConfig(); const errors = validate(config); expect(errors.length).toBe(0); }); @@ -14,7 +14,7 @@ describe('webpack dev config', () => { test('custom', async () => { console.log = jest.fn(); const props = await loadSetup('custom'); - const config = createDevConfig(props).toConfig(); + const config = createClientConfig(props).toConfig(); const errors = validate(config); expect(errors.length).toBe(0); }); diff --git a/test/webpack/prod.test.js b/test/webpack/server.test.js similarity index 74% rename from test/webpack/prod.test.js rename to test/webpack/server.test.js index 019d1a0404..9e4abf7b9b 100644 --- a/test/webpack/prod.test.js +++ b/test/webpack/server.test.js @@ -1,4 +1,4 @@ -import createProdConfig from '@lib/webpack/prod'; +import createServerConfig from '@lib/webpack/server'; import {validate} from 'webpack'; import loadSetup from '../loadSetup'; @@ -6,7 +6,7 @@ describe('webpack production config', () => { test('simple', async () => { console.log = jest.fn(); const props = await loadSetup('simple'); - const config = createProdConfig(props).toConfig(); + const config = createServerConfig(props).toConfig(); const errors = validate(config); expect(errors.length).toBe(0); }); @@ -14,7 +14,7 @@ describe('webpack production config', () => { test('custom', async () => { console.log = jest.fn(); const props = await loadSetup('custom'); - const config = createProdConfig(props).toConfig(); + const config = createServerConfig(props).toConfig(); const errors = validate(config); expect(errors.length).toBe(0); }); From 0058b20d9e6a1ebd02b144f5d4c3f83fb906f099 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 26 Aug 2018 03:17:26 +0800 Subject: [PATCH 094/135] chore: add missing dep & nits :( --- lib/theme/Layout/index.js | 1 - package.json | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index fc677cc836..fdd755a713 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -5,7 +5,6 @@ import styles from './styles.css'; /* eslint-disable react/prefer-stateless-function */ export default class Layout extends React.Component { render() { - console.log(this.props); const {children, pagesData, docsData, location} = this.props; const routeLinks = [...pagesData, ...docsData].map( data => diff --git a/package.json b/package.json index 336ebae2a8..432cb844db 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "babel-preset-react": "^6.24.1", "chalk": "^2.4.1", "chokidar": "^2.0.4", + "classnames": "^2.2.6", "clean-webpack-plugin": "^0.1.19", "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", From ea37e54477e06d81024359f86e26d1ca90011c2f Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 26 Aug 2018 17:06:16 +0800 Subject: [PATCH 095/135] feat: hljs syntax highlighting & nits --- docs/docusaurus.md | 2 +- docs/hello.md | 9 +++++ lib/core/App.js | 4 +- lib/core/components/Markdown/highlight.js | 22 +++++++++++ lib/core/components/Markdown/index.js | 46 ++-------------------- lib/theme/Docs/index.js | 12 +++--- package.json | 1 + website/static/img/slash-introducing.png | Bin 0 -> 15983 bytes 8 files changed, 44 insertions(+), 52 deletions(-) create mode 100644 lib/core/components/Markdown/highlight.js create mode 100644 website/static/img/slash-introducing.png diff --git a/docs/docusaurus.md b/docs/docusaurus.md index 97487e4000..b7bf133d9c 100644 --- a/docs/docusaurus.md +++ b/docs/docusaurus.md @@ -5,7 +5,7 @@ title: docusaurus

    Docusaurus

    - Docusaurus + Docusaurus

    diff --git a/docs/hello.md b/docs/hello.md index a392b2ca54..299d48f962 100644 --- a/docs/hello.md +++ b/docs/hello.md @@ -5,6 +5,15 @@ title: Hello, World ! Hi, Endilie here :) +```py +import hello +def hi(name): + hello(name) + +print('Welcome to my repos!') +``` + + ## Blockquotes > Blockquotes can also be nested... diff --git a/lib/core/App.js b/lib/core/App.js index dd1ca50162..c0b92a8b44 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -3,6 +3,6 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line import docsData from '@generated/docsData'; // eslint-disable-line import pagesData from '@generated/pagesData'; // eslint-disable-line -import config from '@site/siteConfig.js'; //eslint-disable-line +import siteConfig from '@site/siteConfig'; //eslint-disable-line -export default () => renderRoutes(routes, {docsData, pagesData, config}); +export default () => renderRoutes(routes, {docsData, pagesData, siteConfig}); diff --git a/lib/core/components/Markdown/highlight.js b/lib/core/components/Markdown/highlight.js new file mode 100644 index 0000000000..2b2c4f815d --- /dev/null +++ b/lib/core/components/Markdown/highlight.js @@ -0,0 +1,22 @@ +const hljs = require('highlight.js'); +const chalk = require('chalk'); +const escapeHtml = require('escape-html'); + +export default (str, rawLang) => { + if (rawLang === 'text') { + return escapeHtml(str); + } + const lang = rawLang.toLowerCase(); + try { + if (hljs.getLanguage(lang)) { + return hljs.highlight(lang, str).value; + } + } catch (e) { + console.error( + chalk.yellow( + `Highlight.js syntax highlighting for language "${lang}" is not supported.` + ) + ); + } + return hljs.highlightAuto(str).value; +}; diff --git a/lib/core/components/Markdown/index.js b/lib/core/components/Markdown/index.js index e2ca07cffb..c9412efc8d 100644 --- a/lib/core/components/Markdown/index.js +++ b/lib/core/components/Markdown/index.js @@ -1,9 +1,8 @@ -/* eslint-disable react/no-danger */ +/* eslint-disable */ import React from 'react'; import Markdown from 'remarkable'; -import hljs from 'highlight.js'; -import prismjs from 'prismjs'; +import highlight from './highlight'; import anchors from './anchors'; class MarkdownBlock extends React.Component { @@ -36,46 +35,7 @@ class MarkdownBlock extends React.Component { const {siteConfig} = this.props; const md = new Markdown({ langPrefix: 'hljs css language-', - highlight(str, reqLang) { - const lang = - reqLang || (siteConfig.highlight && siteConfig.highlight.defaultLang); - if (lang === 'text') { - return str; - } - if (lang) { - try { - if ( - siteConfig.usePrism === true || - (siteConfig.usePrism && - siteConfig.usePrism.length > 0 && - siteConfig.usePrism.indexOf(lang) !== -1) - ) { - try { - const language = alias[lang] || lang; - // Currently people using prismjs on Node have to individually require() - // every single language (https://github.com/PrismJS/prism/issues/593) - require(`prismjs/components/prism-${language}.min`); // eslint-disable-line - return prismjs.highlight(str, prismjs.languages[language]); - } catch (err) { - console.error(err); - } - } - if (hljs.getLanguage(lang)) { - return hljs.highlight(lang, str).value; - } - } catch (err) { - console.error(err); - } - } - - try { - return hljs.highlightAuto(str).value; - } catch (err) { - console.error(err); - } - - return ''; - }, + highlight: highlight, html: true, linkify: true }); diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index 5a6ff22aa4..e4e1d0862f 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -6,8 +6,8 @@ import Layout from '@theme/Layout'; // eslint-disable-line export default class Docs extends React.Component { render() { - const {location, docsData, config} = this.props; - const currentDoc = docsData.find(data => data.path === location.pathname); + const {route, docsData, siteConfig} = this.props; + const currentDoc = docsData.find(data => data.path === route.path); const highlight = Object.assign( {}, @@ -15,21 +15,21 @@ export default class Docs extends React.Component { version: '9.12.0', theme: 'default' }, - config.highlight + siteConfig.highlight ); // Use user-provided themeUrl if it exists, else construct one from version and theme. const highlightThemeURL = highlight.themeUrl ? highlight.themeUrl - : `//cdnjs.cloudflare.com/ajax/libs/highlight.js/${ + : `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${ highlight.version }/styles/${highlight.theme}.min.css`; return ( - {currentDoc.title || 'Document'} - + {(currentDoc && currentDoc.title) || siteConfig.title} +

    {this.props.children}
    diff --git a/package.json b/package.json index 432cb844db..cd690396b0 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "commander": "^2.16.0", "connect-history-api-fallback": "^1.5.0", "css-loader": "^1.0.0", + "escape-html": "^1.0.3", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", diff --git a/website/static/img/slash-introducing.png b/website/static/img/slash-introducing.png new file mode 100644 index 0000000000000000000000000000000000000000..83945788689839aa89925a581f35d7abe4b546f5 GIT binary patch literal 15983 zcmc(`1yEeux-E>m26qXPpg{rzx8N3>V8Ja|XtZ$;5Hy6~?iSo7xYM{p2-bw)?*Ag$ z`|N%0JLlf>>VL0ZS3&ivUfpx9Dc?7~F~)qaq9l!pMv4Xl1A{3mBdH1l19t(u&p?3# z{-41`A;Z83^TQC+sUu#MozIMdRuP z&FohzpW=i+)@8J3`4)lC4Zsz9EnA}7WnO1@dvjZ90`>vwVPV$(M@vhufR}|L$B(R} zykiJL0SbRX!NWfml`Rdq`&Z=uW!Ibm>kE zFp*v0<_rVAFP|Gql$Ec3$uNU(T9O>U4)({AGEvZAAVwBLZUO${2wx+y24n;jqCH%H z0N%->vj%(;gM3vF$_Q8nt}{sK+x%&4P~~XV=vcMSfM4%T+DajAMYp=f5ufgb1|70mnahD^AVL zrH+F`7uSE%Nhqo7HKyCLY^ip-TCKBO`1qEac?m zffJjX=FcQ`b;-!FF)&hy3HW>`&dyvct*x!UcX(1uN0`i;3bf#1VqjpPq0#2QYakbY zmKYeqa99wX=n^^z$q_*vo#sS%n9WZd;B7QD0@5uGh-~EfBGKb7vSkSHEiq%*y%}4< zWTMi+x(rv$?H-qxmoHwt$f-rHM-Ha05wc`rVuGWis}cGj1z&*D&R2JD8xp*OV85ci zLaSxK(x6-xSZ9#f2Zrzk_mH3u3y;9D6M-`k#E)ZrQTUKFo|tAc@jmLHz7zMQ8H5NGYiE-?80NjL-Vw0thd`oPUM%=NGk&)bVXC%BXIDkETwSZykf)B*$a z4qKo@*APAX?yx>=&+3SV8R#4C9`)x--F*{_mM9KU z+J2K~CsbWCmfWUF5i%ww*;Azl;%f?x#B=McBh&~x`^TAW29NBN``HiWB#E>Pp zeyym##e+Wv?jar|sX@eEt|{d7NN_RzUU=okK<~|xXrUSBzzx3!=pjrv5`Y{A&_4v^ zGP6iL^h3L`Lp{g_1OWpda-00)Hk!YE4Z?}S|G5a~_dQmbzrq&+(03Gms1Wc;^}~2Q zTwA6T`i%%=BY6mUNfw2|myV^vmri_m=G~B&mzQhyQ=_1vq2c!ScKu?q0Fu|-+}zqK z?Ba$^YM~0zp;N6tzQ`CyK`dYq|B9lkTBy!O1xBsXX34Xs!XSxvOxBM6)l78+i5PM= zM;_CJ*w!w5e!D2fQnH4O;iMA6-DqK9;fb-kyStPWl6&D(ZMj1AqABZf1g~%E#Z#5- zz+RCOwP-Lz2{aEzgY!4#O!S`hx7^v^S7w)^i}m$|IpR07eDq!tr%4v?#BbuumuEK0 ze?^Ih8H@%3{ zWLj^Q)dp9Rke;3%7bjs2_65H|QC$eg%gUk^6<1xDu;lg)gNbmuUU9LkS2{RTJY{{i z(H(oeF6Xur|GpXdgNbEI1?1-%%fY(}A~|YqcGOT`6O|xwo}zb;X)wOCBS0M`o=Mu) zlh7+VfYEphgU>6gSRyMe-yNCh7VT0dAbl zn*ukyCVoVw#M&v3T4{Bv^P2Sll}L54p8jHi8|A{&nD-(LjBk6PYVPyj$57E%Mi>g#I?fNcd zc)Q~dA7zbCHHmt{eiY~bm6J+cczR;3;4{T1vGmMO?=j9z%CaCXS!P3s!2YhcO4HB-p0e=R&#GONfPg?#{X%k$SU20mn#BL#hE2-42rnjODm794cW^=< z#UjGPNxcNs0!WB#UwbuUae>(^*Fq$ND%v@rT$7w+S)C*%yXq1Yug$M=nH4njcp?*d zF%T9XYf@L0Utxc@;U?u|l**~782h2=mg&f#AMy5x&;rN*^!yTH$c|cyHhOZ4sO^FvQLP~V=auib1}$&I5?97e z3?diYXgG|>&q;_Cn`-S%BWlLK8K~89(Mt%We6V|t7yyp_YeckW=$Q5G9Q;bWnvSwFTUme-^E-)hU{QSJ7 za?Z{Vzm9P~g=PS$^2x946gf8;zO_fbVdUE7#E?d}RnjQw=FsI++vC-jL7u7<;`snu ztXJO5Yn_F z)1%O<&8+O!T#k+Uz@Z_>xqRvga->ORq%xL@FB*_Tp!h4(5YqSwtcSASTg-_2vpc+L z-iq=*>}Y;30#D>Q58?xmbAC0T`hzivEi2QDbE8u_5dm@4a?$+v-Y6b=dhK5uEK+c;#6Z2`G(B@ zk&L0sCE{0EF0=L!2sG`+N>IFyi>sH3MR$jvP|`;4AGx2h`c@p32b z+GiyGC>3f!@_&_4t)K4;9?3_u+MRffSAZ)f!cBmioWd*+3II&Z-cDWj|r_G!p zGCckb8y0=BblOS{7X}9g;4pG_>VT5Q7xzm=MuzWDtm9YktTlO+FVZl|rG& zh43F|+U>A^ooN$k`KYT3(|?c&8D1EQJia*ksqACg%m|_uTGheW4TrBW%#yosp% zxEM!HrD*;TZ@*VM4mBH5f1|8`E8N`{2`wM9>`Nhz>FJRw)?E$iNd$3J_LCurqfD=C zN%*wTEvCiJxpgw2e?;j{iU;R4Mq!o8-u~P*B;7})unY?K!Z9f(m_3&hyducTtpBo_ zTCs(-+nk}$2%~Ju%utv9 zG$`UGC~ebue}xQaA&>9e1hr9S=RA|L{_Vv&qzrvvUA{plVKA(0dd6S}#$mhd#nJXI zdus#uwh7slN=a;X_r)_)H1y9+h&^;U4xZ_U&+EB3{|x?vxTBNb7!m#NDb5XH*w}B+ zrtV8VuQxbCVU{wuZU%k^3>ud@n3aE=p(1f}QM>4E;_-~F-x0rBm2c=}OCa#kFmx@= zK9*W(AC5tXVLQ)5V^d}-QQmq!H5KuSVX2Yo?>Ra*RIxa!CL#I;$wW<a}9 zI(}0u4(OqD`(2Z1hxPFUvzFG#P2;97-3%}7V6*DZ?h3-f!J33(rV1_0POo;Z(LjF{ zg*tyG`jG4&t9!(wx{$YuACJY9+ozgl%&GK*Z%-z2a_DkZFE6*!$+pkFeGOpMt-aag zZ8NIdlI+`vfDwAuDA9i>1m+XUpwx=!`CO!+_B*9=6|Z5X5%`S&vmGZctEf0UU8;+R zhc}ukV3D)HnC@BmZezgbGQsC^s@$7^l+(@7D|S(~b@gjp|0bUP^O`=9k}(9k;wLolf7qcYOc=P8j@r8$mr^$EPOgEy2)A zCYvIIxm47~`vX5*mj=hR9`Jq(ul;f}k)h||oJIQWVU$nG$B*20qpPc{S_bYLr!$68 zA3gxYRy#*H5&PZU^*$!p#o1Zte9?)Gjcuk(|N3gD-1hBT1FzGm!31`)v$vL(zER6n z7T7!TT40wwQ;Z6=UHx@xAy!Ozt-qDbEY!4&$hu2EQVN_{$LW^H{fqQb-W%kb4R)W)iS#=Js$mbvi=>nxV&f2{k7?TzsT518 zE)#i*e}^uc+HZAB_79J4iK-Z~$f+M8BZpAkU-W+X@ZpNt94Imkye~ImVsLLq#>U1* z1&_|vRM0k*#06g1fhw=K_ z+*||=p)0qA>pV6QGcz;p-&W^Ph2U6PA7PdN`;*?>6kx0yo0>$fe^$MG`7$EUzV#AV zTbIN8KKIvTyml(IerYi=F~Mf#hIdB^RGtU0iLtN^F1w_9jv$cfNwe4WnN4|1PyO9q z(|+sewC;)P+^(P*Jw4EPCGRksrT+Q$#5xF=Jd|H3=lAv)%9Y^>VS8a_R`U4TGMQ%M zX3w<^n1y9|_Lh&SsX}Z>m{?eMC;1{?x2H3m9UV6}H{K`NRCDw5eDp>FoV2-#LE zdrRxpg@vfU`H5rSe}xE1_EulN?lA~TN=}w{ZQ}orxY%BU4i>`j?FD2BDYHceo0!l( zX?A~Y$PY8t43lhJy|!~#34YkoW{=aNm<<6cpPR!UQ^khh-I|rVv$~y`@-|=;C53>k z=@$s>IV+e1Ekm!VK6uT@$jDKlb3IW}7|&B+5kw>;%+y~)zYJM~T0ST3!MT3+jxmBE zEkRk{hPmM#_0vSP?0&vqsoabo+U)fWpExuVT!pqBKL5V`{>Ag>@dhmH?4x~s)a=g@ z<)6mO)x7=%4XtZl69N=ZFA9|9932*7R6tEF!w@GF42O$*cXxM^B}wboC1sG0q3E!K z{TK7w2>Dq*l|;$D;&BI6uupWlySW5r23WbwT4luBF8j+ZH8wMM3vIUx7f|Fp|d%AxMy z$5a?+=2YqAi`%-p5JL91rzFuI$apz>wCZZ5eaJOZu8dR}g@jTCvin*7&M*fwRX-3s zV~T>w$;n@FY;A2Vq^aHu{u-w@3972m-soNa?lhM<~i#*Dq!AwdCH%wEBLdp>Mk znW{6BSt3c_UH3Cz(K9dvqi6T)JrvoNDZQeMFP5DQBib1n9$}nFNr{jLq>|Rq zLd#)xHnz65*4LxwDZfz?`%j)_6aq>|boAsIHz{TYEzH{DT^$8!8D6uOnpe1?R0C$POjA0FyU62h~n_ zm0`-k+_Dy36`+B@E$UYid5KibetL(|bKu;x#lha%4+2C*~(E6K|4S*Gaes<9xZc99LIY2X#`-s8ojI8k$&W&FQeT0G1c=5@;}E!=Y3J>%MTyZ3de!K;ul*)tdg!?Q<5(B%lhgnM^xRh9|mfJ<07 z?etG<{QN(ldonuziSVv#hmhm58&3Z0gquzrsCrFx_7@l<6Mj*>|e;~$Ykl@<8 z{{G^csCMWT$SF1L5-(7 zGgU(tqEJ;8rewTW3~4nzJ^c5Ns8LZ-OQ;k#S^tiBDZ+pt@NWpEV88!LC~RR??91S&eUe4X!UT?f> zsH);>$BgO?Q1^mDGEI6TyL);X8yWyi#=_6;0i$Y?0cObQGn2lgloU8i0Bh_zn6;{b@qr z*tobL@zo-YV(Nr&$t<(`kMYb}wRLq>qfStlYIRLyW(HEl#Kgp$(L^o_OB(D4F6u#; z0K`g*9mRKE-_5h`lr$N!vQ_#f0xw?*wN)Z?wdLd*a zBp8z4`sQzKH4zha7T0)U;BafQpdHAc@H(B`g900*s7|zP^AoFfyVPFZVLZKOg`AOLOZyZ*Y3P6%`h7 z3Mb*CAwWKFf;HT_#rG)ayCUToGYbp*#rjuI@EbdQR{CYBao)~X zKLv(?o12@N8GUci>Zu$<-1g{V`{>4C0zCY4US6A;`GEmBX=&+t=+;)k$B&X=Aos?> zUkt*-!-su&HtjnSvu=t6Ef^oq<4h{LZ?LhoRmAiMMx_@7`TCTd8|zb99^27phx|p~ zbEPT-vqexEGJ9jKp{ua#;P#bJZwR)Qu-mtjD4#&DQ;qQh2Qx>yVYi#Q5S6c0s8rOQGfSMt3ALnA&ty^WYisvr#=sZz(yLL+HtG%W7-E z`Sgp@arp3{?u|r*TDtaixO^%Zi}70LaF{^t3x=i&_|25&P*VZ0EG9_?vae;Xf zWrX42OvK={dka(}2Frf%$WIna4BOIZ2gkCd`(fKvl$Dh&EG*R2;@a9o^j42AMOmvY zjErbrIJ|oY%rq0Q#8_DoyXL+a!Rwb|2&x+zir}qeh-W@wXTSehHQLinY6Qx(yO6I6 zP;z#DZsO2wzbx22rmmwS>zxa198S(hf8XXvW{!`^(i$s8*55TJ~)o3DPaP=Rx&-Rk+`8_G+Ya}#dy=WK<^?tINb6EF{hlnIfMSeBdu z8xau^3f%5a+k<30Hy?{W838@Fv0*lGDAjtB$Ct!ozpP-$!#z=@_ZN4I11g~e`6D5w z>+8C1gjKe+Az8v(B2jmmsQW7Un$+4Zd`d`gJzAIbXZV$gk9wC|z^5^}fWB5)$;r=8 zs@*#{7(O!X+fJ45liApq1cOHoL-{oypk8=ojv1zfxp^3UfDz&%r=QqTx_gw;Q08sZ#s+}0vxPWkYPTy zX;5%*2i4)(ndTFG2%a#lfIw4bCal|FvmsTXHtYtpeC&nK_QGiS4eO=bR+C-7&naKC zWCp^iUYv~-1ojTT!=|8I#Ovw=0?FPcF;pHcjLHKNa$^N2^GcK-fN=+IGLA*+JLr1cR-IL41)`1#yQWJ)I$S6Us6d4<`E82?4HlA3R$Meidn?Std6V&$UVl- zs6^QWBj>6X>It98IaO#YtOyfxGOh9Gj2WBu3dT6Uic}uG3eHnI$i=C2baFyRL4i5q z^S*HdHUW@FU?Xp@&(%!F(!2fa03QXQ!2&p-<5gi%QC2Ao{n^>s`USAA9MGcGRaN0W zRsmZdSXfs$(?E&)mAB7PMMcHjJTERTPLdXOV0(8rC~CIRnR!VDGBs6GQ!~{p?6fsP z@g||5;E5Lmw$(9~5`FG960-VZ*WzIm{;O@z&a3l{ul|e_iU$PIuU_!+)te0xPDe1T z{UR0Pw=<5<{M6o12k#9t<*-}lPvrbvrd}ZbA7pCkxa|MW*cXl^W`3a&!($lFjkiMY61cryBCuWj>+ZXI~CiiB|nh6F!vFlbY zS-H1GuMpHa-LpYq4DlRfB_!a3$PUhcq(5%f=gV@CKtqxcA5YK7=<4E9rdtqz(DqVD8CLN5EUEL0i&JAdXb2&GyPeqku{#l-uo{l zmcvJc$Ip?y`d}@M>%xqY1Ld#$ivj}?9K16~4laNEu;xQLU#>Jmx6r;=?8#>QUn@#yA>EL!2SIBb4MfL=*K-A zrJ$Gll0cGMHNOoBi+T_aK2~SQ3No4IQGDm*-d66=EeUn)1EkW~YWi>f2Ccgy6+J51 z=ym)(?krV?N}5x^&~+v_e`|+5Fg@5UD`TUk?4Uo;7)P$uEH_9^NRUqJnXj{_x)|S{ z$d95BK{TZ+v~<$XcpCZnpVs;G#$XjxlZyQ#hv6qr10(c|^QT6jM+ zTrj`d+fvO~Xlz*aG+n=yV~fQmLJl|xz9RjTk*OXYULE00%EEoEM5nWVoqdsg z3^V(uMMkX--ExI>pc0cDK)H{nyt`eaSA$wj0eW8?bZ&Fa#0WPz-PPmYM*L=f}>DpFMRSzkq-Q^2OZb zN@G^fOoXtBClv)A4@SzQMGq{6n)C#aKDG}8->rw%MExly{5Sq7I3t;ds+3ZaEmu|N zbac0$hG*=5zbIw3iuvW9O3ZYBg%_UZRDDyZf(1pkKxBO9Iff(aV;ITf>4or_DuVavhSQ;(a{m&adBW2T5Foibpw#OI0;Y8J1oqxK*q6E<`ygg!=)bowzgdlhF5?` z@;|V68Kle|S@E1dPpLLaC|;;hDuj&>C%hX!N=7zZm;^mDvCOzuG^Qu0l!dSY2J{v= zAB}%M!Hv8~fkv`p?U0&JQ&ST_8WNsAx3@FxDF6aGw~8+`#(SfdQ=$72= zZq!PsAyPmz0%BuhA5oKqdVK3S=}rOI`tZm|hF)Ngtm|)3njo98^r^0c?t2 zPcg}Oy1Kd`cXGM0Z0FlQe)tRYO-q-{Llp$T#=~>FRB4!W>8&NY&j`{lNrPB_%WLET z|1iLX1eSkrP$n9+-vYb|DIqxy3)1Gs(-Ez{?_t7#gzoN~qcPpL9^Lm%(yecy|T}iCBp1S5i`1oGp_}i{F z^jJ)HBb-#HlJfGsoEEHr>6J~ilatf-6mr^z^WYklRRDJ74Fp zurMT~5xr*Z!(m?3I(vCaVGuR@E8ZKBYU3Y1iypCG?%PC19o5ma-ogA?KEI?U6w?G@WWXAyT z`p93j<>cfH4ObeR^b^>rt`}Cmx8A2&pz!vHSsePFlOq1MC;VyE<6;+nKYp42qRuE| zYa0Skpg?bjlX=1J?j(N6z>-8jMBH6zYpbk0`Z<>-pP=M@y*sksdd!Oj{9bS7S1OAK zq8~5-ClNk)Ll{)oGCCEV<2+cNo~-vVQ=g^DEx&U9rr=XvTwILX3hctUT3cNJquASz zc86;i`gk2ov(9yfM5=8iJBnGHnlJzOAlRDFi{D0?Lx|Tk-b3_Yht7NY+i{XOn#H<@L|fqk$7!r6-6GMt**NE-s+>1;7O-6Vt%-^jU6#L6U{~-OW}y336&T zyhoIW?J@W6LgIk_Hw7?|^&YL^t)fLT{1TGj{}PgD-+j=MJMh=E5hwAAy|_8{ygE}9 zPH!_C`~;X2dwO~XiU!WA^!;`M5?BpuO`GDDeD9HSo6VT1T1N1$qElhC%JfJG30*D@ zR)d3sV`BE$Tl*RuO(t5v1`I=s3OP3THqBiABG6Okl4EQ`BBOa%N%D);X7_{RdxKQo zGVo}1y5Li2$?BIk4;JCFu?ItU1%Aw1w3;5|@)OzbSEsf@LP7wd#mt5?tXJ)nm z7^rnV1_tw`M(1_81h#m+rrPVKeYhbM-YCDw7p6>mA2J?%Ie*&8 zJ3r>ucu#Amj5EG(az#AY*qg5jZ_eQYcxtYH)S&ZX#01A zV)_|N4ZRcZ&fBDy+V=S;9Dwfp)g`fB+O8dkXXv6^gX~;DQ6^=miRcgqm_M|%csa9f zzlSgG%+xJ5ZE+?4<9h=`|FX&`D=f6KA^{Uv|3@bGH+!25@p2nS6++kD#vEP=7JUT~ z3#P2J%QS|XYZg-(PS>?L`CBJ3kEP}0YqVE7 z&hZzl9RNYxuiKwK!;v^QCm1KH!SlO!vbJVw(Kavu)GaXsYqU?QO!3w=Ne{mEplk8J z^bkMDkcyaSv;qV8XG2aX%3ogiXd=abveyLZ=v%tX_E#A|U|XCR4;JiQ@7AbRu_;Tg zj?;a3>}yTOdk1yaxZ?b=BJ*T_Gf5=K6wzsEl<{(ic{KUJ3bC@XT3TA_@&xESAlCzw zXdtGVsw#kMUVIlK=ZLh*fd6-9RqL0IbBwZ$Ut;X1GE6E4NYgoppkKVX6{!G4I@3{s zT_1OB8#FgJ2MC;iMB*^NxQG#KX=4+x=I7^!mko#PFu%Nvr3k$AK4Y%~zI zO2}MU|E#!JR|jaP$6`pM(fH7kQ|te_jUJxjU!qUlFa$=0%xzdCoeBMJoyf>^8kW00z zSf8lN@H>J9*gNI>gX2W+=9@7KOb_JUXx*mKp_5?05)wrl^S7O%zwG{d5rW|5PR_M& zBYkUOhW)Y1|9XIC;mhegx_YjolmMXY zR3iCJ!1oH$Mxh$MqN$eZqG|l%N)AbEyh=S!p@3A_5K%vvKmH=n7mV|3jR)Mhv$Idr zu%O=}M(}Za>%Uow|K%9XG@kfjJCy-%Ens<-qjWV>MkaiIAhb{7)SrDnU6cq<98B%1EN`r=r`Kse3A1N`v703cC7ph!6qUwgCt zqawfeT=pe6VoFZ3$uxXYlc%uiOO(CKKn2xVS}I8@J-;E~iux5%kY|1!bojhIR)m&m zTddp{{H!w%0u7DtrriP07A3b?BIP-$w!TZIfUIsH{_)IfKy$#MiqB$n$r7mKEX7CR zp{BKEPwEDG2Z>HTyYpKdN-raq)i0%2aH?V5f|lJWcjq+vCJKTSzap*DG+k6^!G znHX3YC2I&9w5nKaHl)x~9nN_6$T$ATyWbm4gh}m|SdPTJ+e0+I40iaPc`bjlh7??r zr6;&w^QNS$ZGPI0m-Tk(EeQ11m)(56pVRM6WYZTCFBYcS{-pB9w^E+|pFEkdu&(%* zL6wj;{IzFdhC@cy)r`2Dg}t}mM1YXaBy&aJ0CM;=^lywWKe`4D*^Tn7RF6B zXv!D9nw*h@1Va2T%#xKHpzc@7Fx16~V=o5NUqEym=Di3h*%{;bKW%g6`C$=BO>qAo zPNCLMHQoaR?|p2DPTJVvUDu%A#EbiSdkoMg=Zn{QqeD-i+NYLD6c78choc4bQZj!6 z5LSo?39+!SI;@4T`vE+Qhr$QUwt26Nty1Dsb=1dKhtfj}S~vxFglCEhw~ z+l4r!e%np{p}Rg1PJiAXe=yCA=MGpvAbchnYyaY)NY8Qu${`WlNj(j57SCctEJM9e zP_lX_cut2v%ac z4GjV-)#9n@T4ah0T`Q}?sfYfeKtqEf4<;U~qlgU{5W@AUcN=FOMl;38Q2&h8K%_&M z&_Hw$WnAsQ5ljtC=Yq(h8c{)6em*}YO`UoS;Cn6omaR9-7K0OQ@60?QInpbOGo?JIbuKii)UtfBiS1x6dPWL__}R zsD}t|<_mM7Yf+2Vo}mn_MBxB`h(A3aZRBPl*48eN!8ogAzd20-AiOAlB4gi_BL~9?nm_L4DJU?*$?yu7V%+bE7G{;S|J^aTto(ongBdf)mh5??} zcLVLmf<4IY>*1v{PXFY{#N7E}Z?J{C^O?Im?y{zM?&;QmKC;BX;Sd&Q;xiV>h=9nK zsDJ(boh6IW?Ds#q@q zq@uba`0pYvk~8Mv7ZGSf4rHRX$3{#5eD+9h_8Llo8?_wre7)uE#n_D^BtH$gyuRjk z>2eSLn0n*`7;DS!h4Z3=QuEKv%L*b-$amO%`uxkmAD2|-ZjD`s7Y39Q_x`^}#E}T( zAefzz;Xq@XjSDe;vWSmBfsc=`u<*o^NLO=ANP$h=^jyh=08P!*~DfZDyM5 b_wbd&t}l-+I5&WU Date: Sun, 26 Aug 2018 20:27:46 +0800 Subject: [PATCH 096/135] chore: add another react pages examples --- docs/hello.md | 11 -------- lib/commands/start.js | 2 +- lib/theme/Layout/styles.css | 1 + lib/theme/Loading.js | 2 +- package.json | 1 + website/components/Todo/index.js | 4 --- website/pages/index.js | 3 +- website/pages/youtube.js | 32 ++++++++++++++++++++++ website/static/css/{todo.css => basic.css} | 0 yarn.lock | 26 +++++++++++++++++- 10 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 website/pages/youtube.js rename website/static/css/{todo.css => basic.css} (100%) diff --git a/docs/hello.md b/docs/hello.md index 299d48f962..dc816910fe 100644 --- a/docs/hello.md +++ b/docs/hello.md @@ -3,17 +3,6 @@ id: hello title: Hello, World ! --- -Hi, Endilie here :) - -```py -import hello -def hi(name): - hello(name) - -print('Welcome to my repos!') -``` - - ## Blockquotes > Blockquotes can also be nested... diff --git a/lib/commands/start.js b/lib/commands/start.js index 3dcc529b73..5b7a96e831 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -50,7 +50,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { } const port = await getPort(cliOptions.port); - const hotPort = await getPort(5555); + const hotPort = await getPort(port + 1); const {baseUrl} = props; // create compiler from generated webpack config diff --git a/lib/theme/Layout/styles.css b/lib/theme/Layout/styles.css index fe65cd056e..55e9df9a57 100644 --- a/lib/theme/Layout/styles.css +++ b/lib/theme/Layout/styles.css @@ -1,5 +1,6 @@ .footer { color: #777; + margin-top: 30px; padding: 10px 15px; height: 20px; text-align: center; diff --git a/lib/theme/Loading.js b/lib/theme/Loading.js index c4af8d5525..692fe085f9 100644 --- a/lib/theme/Loading.js +++ b/lib/theme/Loading.js @@ -11,5 +11,5 @@ export default props => {
    ); } - return
    Loading...
    ; + return
    Loading...
    ; }; diff --git a/package.json b/package.json index cd690396b0..d67af924e5 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "react-loadable": "^5.5.0", "react-router-config": "^1.0.0-beta.4", "react-router-dom": "^4.3.1", + "react-youtube": "^7.6.0", "remarkable": "^1.7.1", "semver": "^5.5.0", "static-site-generator-webpack-plugin": "endiliey/static-site-generator-webpack-plugin#master", diff --git a/website/components/Todo/index.js b/website/components/Todo/index.js index ec158d4a28..50e2291d1f 100644 --- a/website/components/Todo/index.js +++ b/website/components/Todo/index.js @@ -181,10 +181,6 @@ class TodoApp extends React.Component { return (
    - - Todo App - -

    todos

    - Homepage + Todo App + diff --git a/website/pages/youtube.js b/website/pages/youtube.js new file mode 100644 index 0000000000..b2c92c60e8 --- /dev/null +++ b/website/pages/youtube.js @@ -0,0 +1,32 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import YouTube from 'react-youtube'; +import Layout from '@theme/Layout'; + +export default class Player extends React.Component { + render() { + const opts = { + height: '390', + width: '640', + playerVars: { + autoplay: 1 + } + }; + + return ( + + + My Youtube + +

    + +

    +
    + ); + } + + _onReady(event) { + // access to player in all event handlers via event.target + event.target.playVideo(); + } +} diff --git a/website/static/css/todo.css b/website/static/css/basic.css similarity index 100% rename from website/static/css/todo.css rename to website/static/css/basic.css diff --git a/yarn.lock b/yarn.lock index f497b28941..1b464c375f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4284,6 +4284,10 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" +load-script@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" + loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" @@ -5422,7 +5426,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: +prop-types@^15.5.0, prop-types@^15.5.3, prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -5617,6 +5621,14 @@ react-side-effect@^1.1.0: exenv "^1.2.1" shallowequal "^1.0.1" +react-youtube@^7.6.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/react-youtube/-/react-youtube-7.6.0.tgz#ea4b7a9396f635b9f2a9f03bfe2a39b93cbdd59d" + dependencies: + lodash "^4.17.4" + prop-types "^15.5.3" + youtube-player "^5.4.0" + react@^16.4.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32" @@ -6129,6 +6141,10 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +sister@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sister/-/sister-3.0.1.tgz#a36ba6a1d1e46415ba16cb4ecefe14cbd8d82d1f" + sisteransi@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" @@ -7261,3 +7277,11 @@ yargs@~3.10.0: ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" + +youtube-player@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/youtube-player/-/youtube-player-5.5.0.tgz#95f058534f9544586185551d0d2d33f381f6587a" + dependencies: + debug "^2.6.6" + load-script "^1.0.0" + sister "^3.0.0" From ef17da741aff0f2b92f48538b7719ca3dcac944f Mon Sep 17 00:00:00 2001 From: endiliey Date: Tue, 28 Aug 2018 22:44:33 +0800 Subject: [PATCH 097/135] chore: nits && lint --- lib/commands/build.js | 5 +++-- lib/commands/start.js | 2 +- website/components/Todo/index.js | 2 +- website/pages/youtube.js | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/commands/build.js b/lib/commands/build.js index cbb6501d7c..551fa5be06 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -39,10 +39,11 @@ module.exports = async function build(siteDir, cliOptions = {}) { const serverConfig = createServerConfig(props).toConfig(); const clientConfig = createClientConfig(props).toConfig(); - // we build the client bundles first + // Build the client bundles first. + // We cannot run them in parallel because the server need to pickup the correct client bundle name await compile(clientConfig); - // then we build the server bundles (render the static HTML and pick client bundle) + // Build the server bundles (render the static HTML and pick client bundle) await compile(serverConfig); // copy static files diff --git a/lib/commands/start.js b/lib/commands/start.js index 5b7a96e831..3d766194d9 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -95,7 +95,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { // enable HTTP range requests app.use(range); - // rewrite request to `/` since this is a SPA + // rewrite request to `/` since dev is only a SPA app.use( convert( history({ diff --git a/website/components/Todo/index.js b/website/components/Todo/index.js index 50e2291d1f..f0da5a519b 100644 --- a/website/components/Todo/index.js +++ b/website/components/Todo/index.js @@ -36,7 +36,7 @@ const todos = [ }, { id: '63a871b2-0b6f-4422-9c35-304bc680a4b7', - title: 'Earn money through open source work.', + title: 'Contribute to open source.', completed: false }, { diff --git a/website/pages/youtube.js b/website/pages/youtube.js index b2c92c60e8..04a7709620 100644 --- a/website/pages/youtube.js +++ b/website/pages/youtube.js @@ -19,7 +19,8 @@ export default class Player extends React.Component { My Youtube

    - + {/* this is a React-youtube component */ } +

    ); From 9965eec798d9ecd78e36430297ebe430ccad628d Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 29 Aug 2018 23:57:26 +0800 Subject: [PATCH 098/135] feat: throw error if there is wrong field on siteConfig.js --- lib/core/components/Markdown/highlight.js | 2 +- lib/load/config.js | 20 ++++++++++++++++++- .../__fixtures__/wrong-site/siteConfig.js | 10 ++++++++++ test/load/config.test.js | 13 ++++++++++-- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 test/load/__fixtures__/wrong-site/siteConfig.js diff --git a/lib/core/components/Markdown/highlight.js b/lib/core/components/Markdown/highlight.js index 2b2c4f815d..643856b550 100644 --- a/lib/core/components/Markdown/highlight.js +++ b/lib/core/components/Markdown/highlight.js @@ -3,7 +3,7 @@ const chalk = require('chalk'); const escapeHtml = require('escape-html'); export default (str, rawLang) => { - if (rawLang === 'text') { + if (rawLang === 'text' || !rawLang) { return escapeHtml(str); } const lang = rawLang.toLowerCase(); diff --git a/lib/load/config.js b/lib/load/config.js index b5269b5a2f..92540265e4 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -18,9 +18,27 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { 'projectName', 'baseUrl' ]; + const optionalFields = [ + 'customDocsPath', + 'themePath', + 'highlight', + 'markdownPlugins' + ]; const missingFields = requiredFields.filter(field => !config[field]); if (missingFields && missingFields.length > 0) { - throw new Error(`${missingFields.join(', ')} are missing in siteConfig.js`); + throw new Error( + `${missingFields.join(', ')} fields are missing in siteConfig.js` + ); } + + const uselessFields = Object.keys(config).filter( + field => ![...requiredFields, ...optionalFields].includes(field) + ); + if (uselessFields && uselessFields.length > 0) { + throw new Error( + `${uselessFields.join(', ')} fields are useless in siteConfig.js` + ); + } + return config; }; diff --git a/test/load/__fixtures__/wrong-site/siteConfig.js b/test/load/__fixtures__/wrong-site/siteConfig.js new file mode 100644 index 0000000000..c84b9e4594 --- /dev/null +++ b/test/load/__fixtures__/wrong-site/siteConfig.js @@ -0,0 +1,10 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/', + useLessField: 'what', + superman: 'lol', + admin: 'endi' +}; diff --git a/test/load/config.test.js b/test/load/config.test.js index f0015a0770..817346229f 100644 --- a/test/load/config.test.js +++ b/test/load/config.test.js @@ -20,7 +20,16 @@ describe('loadConfig', () => { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"tagline, organizationName, projectName are missing in siteConfig.js"` + `"tagline, organizationName, projectName fields are missing in siteConfig.js"` + ); + }); + + test('website with useless field (wrong field) in siteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'wrong-site'); + expect(() => { + loadConfig(siteDir); + }).toThrowErrorMatchingInlineSnapshot( + `"useLessField, superman, admin fields are useless in siteConfig.js"` ); }); @@ -29,7 +38,7 @@ describe('loadConfig', () => { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"title, tagline, organizationName, projectName, baseUrl are missing in siteConfig.js"` + `"title, tagline, organizationName, projectName, baseUrl fields are missing in siteConfig.js"` ); }); }); From 8c6bc6dd38bdea134e99e64f1c9487a32d514834 Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 30 Aug 2018 00:29:25 +0800 Subject: [PATCH 099/135] feat: able to specify host for dev (e.g: 0.0.0.0) --- bin/munseo.js | 1 + lib/commands/start.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/bin/munseo.js b/bin/munseo.js index b99b13ad98..8a1e3aa22d 100644 --- a/bin/munseo.js +++ b/bin/munseo.js @@ -53,6 +53,7 @@ program .command('start [siteDir]') .description('Start development server') .option('-p, --port ', 'use specified port (default: 3000)') + .option('-h, --host ', 'use specified host (default: localhost') .option('-nw, --no-watch ', 'disable live reload (default: false)') .action((siteDir = '.', {port, noWatch}) => { wrapCommand(start)(path.resolve(siteDir), {port, noWatch}); diff --git a/lib/commands/start.js b/lib/commands/start.js index 3d766194d9..7c477511e5 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -14,6 +14,10 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../load'); const createClientConfig = require('../webpack/client'); +function getHost(reqHost) { + return reqHost || 'localhost'; +} + async function getPort(reqPort) { portfinder.basePort = parseInt(reqPort, 10) || 3000; const port = await portfinder.getPortPromise(); @@ -51,6 +55,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { const port = await getPort(cliOptions.port); const hotPort = await getPort(port + 1); + const host = getHost(cliOptions.host); const {baseUrl} = props; // create compiler from generated webpack config @@ -85,6 +90,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { }, logLevel: 'error', port, + host, add: app => { // serve static files const staticDir = path.resolve(siteDir, 'static'); From 2b5ee3e8697f9a12b1f9e97daa19c352433beea3 Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 30 Aug 2018 01:03:38 +0800 Subject: [PATCH 100/135] feat: enable custom theme with eject --- bin/munseo.js | 9 ++++++++- lib/commands/eject.js | 16 ++++++++++++++++ lib/index.js | 2 ++ lib/load/config.js | 1 - lib/load/index.js | 18 +++++++++++++----- package.json | 1 + 6 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 lib/commands/eject.js diff --git a/bin/munseo.js b/bin/munseo.js index 8a1e3aa22d..fafbb8095b 100644 --- a/bin/munseo.js +++ b/bin/munseo.js @@ -4,7 +4,7 @@ const chalk = require('chalk'); const semver = require('semver'); const path = require('path'); const program = require('commander'); -const {build, init, start} = require('../lib'); +const {build, eject, init, start} = require('../lib'); const requiredVersion = require('../package.json').engines.node; if (!semver.satisfies(process.version, requiredVersion)) { @@ -42,6 +42,13 @@ program wrapCommand(build)(path.resolve(siteDir), {skipImageCompression}); }); +program + .command('eject [siteDir]') + .description('copy the default theme into website folder for customization.') + .action((siteDir = '.') => { + wrapCommand(eject)(path.resolve(siteDir)); + }); + program .command('init [projectDir]') .description('Initialize website') diff --git a/lib/commands/eject.js b/lib/commands/eject.js new file mode 100644 index 0000000000..42c630747d --- /dev/null +++ b/lib/commands/eject.js @@ -0,0 +1,16 @@ +const fs = require('fs-extra'); +const chalk = require('chalk'); +const path = require('path'); + +module.exports = async function eject(siteDir) { + const defaultTheme = path.resolve(__dirname, '..', 'theme'); + const customTheme = path.resolve(siteDir, 'theme'); + await fs.copy(defaultTheme, customTheme); + + const relativeDir = path.relative(process.cwd(), customTheme); + console.log( + `\n${chalk.green('Success!')} Copied default theme files to ${chalk.cyan( + relativeDir + )}.\n` + ); +}; diff --git a/lib/index.js b/lib/index.js index 7594a1260b..03c0a0dab0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,9 +1,11 @@ const build = require('./commands/build'); const init = require('./commands/init'); const start = require('./commands/start'); +const eject = require('./commands/eject'); module.exports = { build, + eject, init, start }; diff --git a/lib/load/config.js b/lib/load/config.js index 92540265e4..c106e9e0ff 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -20,7 +20,6 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { ]; const optionalFields = [ 'customDocsPath', - 'themePath', 'highlight', 'markdownPlugins' ]; diff --git a/lib/load/index.js b/lib/load/index.js index 7ce9b4540a..f31e13eeb5 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -34,11 +34,19 @@ module.exports = async function load(siteDir) { const outDir = path.resolve(siteDir, 'build'); // resolve the theme - const themePath = - siteConfig.themePath && - fs.existsSync(path.resolve(siteDir, siteConfig.themePath)) - ? siteConfig.themePath - : path.resolve(__dirname, '../theme'); + const customThemePath = path.resolve(siteDir, 'theme'); + const themePath = fs.existsSync(customThemePath) + ? customThemePath + : path.resolve(__dirname, '../theme'); + + const themeComponents = ['Docs', 'Loading', 'NotFound']; + themeComponents.forEach(component => { + if (!require.resolve(path.join(themePath, component))) { + throw new Error( + `Failed to load ${themePath}/${component}. It does not exist.` + ); + } + }); const baseUrl = siteConfig.baseUrl || '/'; diff --git a/package.json b/package.json index d67af924e5..01d9b0898d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "munseo": "node bin/munseo", "start": "node bin/munseo start website", "build": "node bin/munseo build website", + "eject": "node bin/munseo eject website", "prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"", "test": "jest --config test/jest.config.js" From 10b1a38762a0843f7f7543a6e4ae8b2d11e5f8ac Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 30 Aug 2018 03:30:44 +0800 Subject: [PATCH 101/135] feat: allow user to modify generated webpack config --- lib/commands/build.js | 12 ++++- lib/commands/start.js | 8 +++ lib/load/config.js | 4 +- lib/webpack/client.js | 5 ++ lib/webpack/server.js | 4 ++ lib/webpack/utils.js | 28 ++++++++++ package.json | 1 + test/webpack/utils.test.js | 107 +++++++++++++++++++++++++++++++++++++ yarn.lock | 6 +++ 9 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 lib/webpack/utils.js create mode 100644 test/webpack/utils.test.js diff --git a/lib/commands/build.js b/lib/commands/build.js index 551fa5be06..a2da9b3dda 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -6,6 +6,7 @@ const globby = require('globby'); const load = require('../load'); const createServerConfig = require('../webpack/server'); const createClientConfig = require('../webpack/client'); +const {applyConfigureWebpack} = require('../webpack/utils'); function compile(config) { return new Promise((resolve, reject) => { @@ -36,8 +37,15 @@ module.exports = async function build(siteDir, cliOptions = {}) { const props = await load(siteDir); - const serverConfig = createServerConfig(props).toConfig(); - const clientConfig = createClientConfig(props).toConfig(); + let serverConfig = createServerConfig(props).toConfig(); + let clientConfig = createClientConfig(props).toConfig(); + + // apply user webpack config + const { + siteConfig: {configureWebpack} + } = props; + clientConfig = applyConfigureWebpack(configureWebpack, clientConfig, false); + serverConfig = applyConfigureWebpack(configureWebpack, serverConfig, true); // Build the client bundles first. // We cannot run them in parallel because the server need to pickup the correct client bundle name diff --git a/lib/commands/start.js b/lib/commands/start.js index 7c477511e5..a95d15d050 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -13,6 +13,7 @@ const serve = require('webpack-serve'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../load'); const createClientConfig = require('../webpack/client'); +const {applyConfigureWebpack} = require('../webpack/utils'); function getHost(reqHost) { return reqHost || 'localhost'; @@ -72,6 +73,13 @@ module.exports = async function start(siteDir, cliOptions = {}) { } ]); config = config.toConfig(); + + // apply user webpack config + const { + siteConfig: {configureWebpack} + } = props; + config = applyConfigureWebpack(configureWebpack, config, false); + const compiler = webpack(config); // webpack-serve diff --git a/lib/load/config.js b/lib/load/config.js index c106e9e0ff..fd325ce08f 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -21,7 +21,9 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { const optionalFields = [ 'customDocsPath', 'highlight', - 'markdownPlugins' + 'markdownPlugins', + 'configureWebpack', + 'chainWebpack' ]; const missingFields = requiredFields.filter(field => !config[field]); if (missingFields && missingFields.length > 0) { diff --git a/lib/webpack/client.js b/lib/webpack/client.js index 8c438ebc71..c544300df9 100644 --- a/lib/webpack/client.js +++ b/lib/webpack/client.js @@ -3,6 +3,7 @@ const webpackNiceLog = require('webpack-nicelog'); const {StatsWriterPlugin} = require('webpack-stats-plugin'); const cleanWebpackPlugin = require('clean-webpack-plugin'); const createBaseConfig = require('./base'); +const {applyChainWebpack} = require('./utils'); module.exports = function createClientConfig(props) { const config = createBaseConfig(props); @@ -21,5 +22,9 @@ module.exports = function createClientConfig(props) { // show compilation progress bar and build time config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]); + + // user extended webpack-chain config + applyChainWebpack(props.siteConfig.chainWebpack, config, false); + return config; }; diff --git a/lib/webpack/server.js b/lib/webpack/server.js index bc236de34d..d55481ffd0 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -2,6 +2,7 @@ const path = require('path'); const staticSiteGenerator = require('static-site-generator-webpack-plugin'); const webpackNiceLog = require('webpack-nicelog'); const createBaseConfig = require('./base'); +const {applyChainWebpack} = require('./utils'); module.exports = function createServerConfig(props) { const config = createBaseConfig(props, true); @@ -32,5 +33,8 @@ module.exports = function createServerConfig(props) { .plugin('niceLog') .use(webpackNiceLog, [{name: 'Server', color: 'yellow'}]); + // user extended webpack-chain config + applyChainWebpack(props.siteConfig.chainWebpack, config, true); + return config; }; diff --git a/lib/webpack/utils.js b/lib/webpack/utils.js new file mode 100644 index 0000000000..9ce3d29a2c --- /dev/null +++ b/lib/webpack/utils.js @@ -0,0 +1,28 @@ +const merge = require('webpack-merge'); + +// Modify the generated webpack config with normal webpack config +function applyConfigureWebpack(userConfig, config, isServer) { + if (typeof userConfig === 'object') { + return merge(config, userConfig); + } + if (typeof userConfig === 'function') { + const res = userConfig(config, isServer); + if (res && typeof res === 'object') { + return merge(config, res); + } + } + return config; +} + +// Modify the generated webpack config with webpack-chain API +function applyChainWebpack(userChainWebpack, config, isServer) { + if (userChainWebpack) { + userChainWebpack(config, isServer); + } + +} + +module.exports = { + applyConfigureWebpack, + applyChainWebpack +}; diff --git a/package.json b/package.json index 01d9b0898d..5502c30878 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "style-loader": "^0.22.1", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", + "webpack-merge": "^4.1.4", "webpack-nicelog": "^2.2.1", "webpack-serve": "^2.0.2", "webpack-stats-plugin": "^0.2.1" diff --git a/test/webpack/utils.test.js b/test/webpack/utils.test.js new file mode 100644 index 0000000000..8ffd610fbe --- /dev/null +++ b/test/webpack/utils.test.js @@ -0,0 +1,107 @@ +import {validate} from 'webpack'; +import path from 'path'; +import Config from 'webpack-chain'; + +import {applyConfigureWebpack, applyChainWebpack} from '@lib/webpack/utils'; + +describe('extending generated webpack config', () => { + test('direct mutation on generated webpack config object', async () => { + // fake generated webpack config + let config = { + output: { + path: __dirname, + filename: 'bundle.js' + } + }; + + /* eslint-disable */ + const configureWebpack = (generatedConfig, isServer) => { + if (!isServer) { + generatedConfig.entry = 'entry.js'; + generatedConfig.output = { + path: path.join(__dirname, 'dist'), + filename: 'new.bundle.js' + }; + } + }; + /* eslint-enable */ + + config = applyConfigureWebpack(configureWebpack, config, false); + expect(config).toEqual({ + entry: 'entry.js', + output: { + path: path.join(__dirname, 'dist'), + filename: 'new.bundle.js' + } + }); + const errors = validate(config); + + console.log(errors); + expect(errors.length).toBe(0); + }); + + test('webpack-merge with user webpack config object', async () => { + // fake generated webpack config + let config = { + output: { + path: __dirname, + filename: 'bundle.js' + } + }; + + /* eslint-disable */ + const configureWebpack = { + entry: 'entry.js', + output: { + path: path.join(__dirname, 'dist'), + filename: 'new.bundle.js' + } + }; + /* eslint-enable */ + + config = applyConfigureWebpack(configureWebpack, config, false); + expect(config).toEqual({ + entry: 'entry.js', + output: { + path: path.join(__dirname, 'dist'), + filename: 'new.bundle.js' + } + }); + const errors = validate(config); + expect(errors.length).toBe(0); + }); + + test('use webpack-chain API', async () => { + // fake generated webpack config in webpack-chain format + let config = new Config(); + config.output.path(__dirname).filename('bundle.js'); + + // user chainWebpack + /* eslint-disable */ + const chainWebpack = (oldConfig, isServer) => { + if (!isServer) { + oldConfig.entry('main').add('./entry.js'); + oldConfig.output + .path(path.join(__dirname, 'dist')) + .filename('new.bundle.js'); + } + }; + /* eslint-enable */ + + applyChainWebpack(chainWebpack, config, false); + + // transform to webpack configuration object format + config = config.toConfig(); + expect(config).toEqual({ + output: { + path: path.join(__dirname, 'dist'), + filename: 'new.bundle.js' + }, + entry: { + main: ['./entry.js'] + } + }); + const errors = validate(config); + expect(errors.length).toBe(0); + }); +}); diff --git a/yarn.lock b/yarn.lock index 1b464c375f..4897e32bd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6975,6 +6975,12 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0: loglevelnext "^1.0.1" uuid "^3.1.0" +webpack-merge@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.4.tgz#0fde38eabf2d5fd85251c24a5a8c48f8a3f4eb7b" + dependencies: + lodash "^4.17.5" + webpack-nicelog@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.2.1.tgz#e3458003ce0d98966e930657176fb4eb6f536b85" From 828d99dc8e99c89a8f4fde42e1dc7e7984766968 Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 3 Sep 2018 23:30:13 +0800 Subject: [PATCH 102/135] refactor: load theme --- lib/load/index.js | 16 ++-------------- lib/load/theme.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 lib/load/theme.js diff --git a/lib/load/index.js b/lib/load/index.js index f31e13eeb5..f5cbbcd7a5 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -1,8 +1,8 @@ -const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); const loadDocs = require('./docs'); const loadPages = require('./pages'); +const loadTheme = require('./theme'); const {generate} = require('./utils'); const genRoutesConfig = require('./routes'); @@ -34,19 +34,7 @@ module.exports = async function load(siteDir) { const outDir = path.resolve(siteDir, 'build'); // resolve the theme - const customThemePath = path.resolve(siteDir, 'theme'); - const themePath = fs.existsSync(customThemePath) - ? customThemePath - : path.resolve(__dirname, '../theme'); - - const themeComponents = ['Docs', 'Loading', 'NotFound']; - themeComponents.forEach(component => { - if (!require.resolve(path.join(themePath, component))) { - throw new Error( - `Failed to load ${themePath}/${component}. It does not exist.` - ); - } - }); + const themePath = loadTheme(siteDir); const baseUrl = siteConfig.baseUrl || '/'; diff --git a/lib/load/theme.js b/lib/load/theme.js new file mode 100644 index 0000000000..0aa529c145 --- /dev/null +++ b/lib/load/theme.js @@ -0,0 +1,20 @@ +const fs = require('fs-extra'); +const path = require('path'); + +module.exports = function loadConfig(siteDir) { + const customThemePath = path.resolve(siteDir, 'theme'); + const themePath = fs.existsSync(customThemePath) + ? customThemePath + : path.resolve(__dirname, '../theme'); + + const themeComponents = ['Docs', 'Loading', 'NotFound']; + themeComponents.forEach(component => { + if (!require.resolve(path.join(themePath, component))) { + throw new Error( + `Failed to load ${themePath}/${component}. It does not exist.` + ); + } + }); + + return themePath; +}; From 1ff67334643aa54595ca321534276fdad0a261a1 Mon Sep 17 00:00:00 2001 From: endiliey Date: Tue, 4 Sep 2018 23:36:51 +0800 Subject: [PATCH 103/135] feat: add loadEnv to check if translation / versioning is enabled --- lib/load/{docs.js => docs/index.js} | 2 +- lib/load/env.js | 39 ++++ lib/load/index.js | 5 + lib/webpack/utils.js | 1 - .../__fixtures__/translated-site/languages.js | 178 ++++++++++++++++++ .../translated-site/siteConfig.js | 7 + .../transversioned-site/languages.js | 178 ++++++++++++++++++ .../transversioned-site/siteConfig.js | 7 + .../transversioned-site/versions.json | 4 + .../__fixtures__/versioned-site/siteConfig.js | 7 + .../__fixtures__/versioned-site/versions.json | 4 + test/load/__snapshots__/env.test.js.snap | 119 ++++++++++++ test/load/__snapshots__/pages.test.js.snap | 8 +- test/load/__snapshots__/routes.test.js.snap | 28 +-- test/load/env.test.js | 41 ++++ 15 files changed, 608 insertions(+), 20 deletions(-) rename lib/load/{docs.js => docs/index.js} (94%) create mode 100644 lib/load/env.js create mode 100644 test/load/__fixtures__/translated-site/languages.js create mode 100644 test/load/__fixtures__/translated-site/siteConfig.js create mode 100644 test/load/__fixtures__/transversioned-site/languages.js create mode 100644 test/load/__fixtures__/transversioned-site/siteConfig.js create mode 100644 test/load/__fixtures__/transversioned-site/versions.json create mode 100644 test/load/__fixtures__/versioned-site/siteConfig.js create mode 100644 test/load/__fixtures__/versioned-site/versions.json create mode 100644 test/load/__snapshots__/env.test.js.snap create mode 100644 test/load/env.test.js diff --git a/lib/load/docs.js b/lib/load/docs/index.js similarity index 94% rename from lib/load/docs.js rename to lib/load/docs/index.js index 7483b9d2e7..eb906b9a10 100644 --- a/lib/load/docs.js +++ b/lib/load/docs/index.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const fm = require('front-matter'); const globby = require('globby'); -const {encodePath, fileToPath} = require('./utils'); +const {encodePath, fileToPath} = require('../utils'); function parse(fileString) { if (!fm.test(fileString)) { diff --git a/lib/load/env.js b/lib/load/env.js new file mode 100644 index 0000000000..d53b46f416 --- /dev/null +++ b/lib/load/env.js @@ -0,0 +1,39 @@ +const fs = require('fs-extra'); +const path = require('path'); + +module.exports = function loadEnv({siteDir, siteConfig}) { + // Translation + const translation = { + enabled: false, + enabledLanguages: [] + }; + + const languagesFile = path.join(siteDir, 'languages.js'); + if (fs.existsSync(languagesFile)) { + translation.enabled = true; + const languages = require(languagesFile); + translation.enabledLanguages = languages.filter(lang => lang.enabled); + } + + // Versioning + const versioning = { + enabled: false, + latestVersion: null, + defaultVersion: null, + versions: [] + }; + + const versionsJSONFile = path.join(siteDir, 'versions.json'); + if (fs.existsSync(versionsJSONFile)) { + versioning.enabled = true; + versioning.versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8')); + versioning.latestVersion = versioning.versions[0]; + const {defaultVersionShown} = siteConfig; + versioning.defaultVersion = defaultVersionShown || versioning.latestVersion; + } + + return { + translation, + versioning + }; +}; diff --git a/lib/load/index.js b/lib/load/index.js index f5cbbcd7a5..7cebbc0271 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -1,6 +1,7 @@ const path = require('path'); const loadConfig = require('./config'); const loadDocs = require('./docs'); +const loadEnv = require('./env'); const loadPages = require('./pages'); const loadTheme = require('./theme'); const {generate} = require('./utils'); @@ -10,6 +11,9 @@ module.exports = async function load(siteDir) { // siteConfig const siteConfig = loadConfig(siteDir); + // env + const env = loadEnv({siteDir, siteConfig}); + // docs const docsDir = path.resolve( siteDir, @@ -43,6 +47,7 @@ module.exports = async function load(siteDir) { siteDir, docsDir, docsData, + env, pagesDir, pagesData, outDir, diff --git a/lib/webpack/utils.js b/lib/webpack/utils.js index 9ce3d29a2c..369bb5db87 100644 --- a/lib/webpack/utils.js +++ b/lib/webpack/utils.js @@ -19,7 +19,6 @@ function applyChainWebpack(userChainWebpack, config, isServer) { if (userChainWebpack) { userChainWebpack(config, isServer); } - } module.exports = { diff --git a/test/load/__fixtures__/translated-site/languages.js b/test/load/__fixtures__/translated-site/languages.js new file mode 100644 index 0000000000..14c4aca911 --- /dev/null +++ b/test/load/__fixtures__/translated-site/languages.js @@ -0,0 +1,178 @@ +const languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + { + enabled: false, + name: '日本語', + tag: 'ja', + }, + { + enabled: false, + name: 'العربية', + tag: 'ar', + }, + { + enabled: false, + name: 'Bosanski', + tag: 'bs-BA', + }, + { + enabled: false, + name: 'Català', + tag: 'ca', + }, + { + enabled: false, + name: 'Čeština', + tag: 'cs', + }, + { + enabled: false, + name: 'Dansk', + tag: 'da', + }, + { + enabled: false, + name: 'Deutsch', + tag: 'de', + }, + { + enabled: false, + name: 'Ελληνικά', + tag: 'el', + }, + { + enabled: true, + name: 'Español', + tag: 'es-ES', + }, + { + enabled: false, + name: 'فارسی', + tag: 'fa-IR', + }, + { + enabled: false, + name: 'Suomi', + tag: 'fi', + }, + { + enabled: false, + name: 'Français', + tag: 'fr', + }, + { + enabled: false, + name: 'עִברִית', + tag: 'he', + }, + { + enabled: false, + name: 'Magyar', + tag: 'hu', + }, + { + enabled: false, + name: 'Bahasa Indonesia', + tag: 'id-ID', + }, + { + enabled: false, + name: 'Italiano', + tag: 'it', + }, + { + enabled: false, + name: 'Afrikaans', + tag: 'af', + }, + { + enabled: false, + name: '한국어', + tag: 'ko', + }, + { + enabled: false, + name: 'मराठी', + tag: 'mr-IN', + }, + { + enabled: false, + name: 'Nederlands', + tag: 'nl', + }, + { + enabled: false, + name: 'Norsk', + tag: 'no-NO', + }, + { + enabled: false, + name: 'Polskie', + tag: 'pl', + }, + { + enabled: false, + name: 'Português', + tag: 'pt-PT', + }, + { + enabled: false, + name: 'Português (Brasil)', + tag: 'pt-BR', + }, + { + enabled: true, + name: 'Română', + tag: 'ro', + }, + { + enabled: false, + name: 'Русский', + tag: 'ru', + }, + { + enabled: false, + name: 'Slovenský', + tag: 'sk-SK', + }, + { + enabled: false, + name: 'Српски језик (Ћирилица)', + tag: 'sr', + }, + { + enabled: false, + name: 'Svenska', + tag: 'sv-SE', + }, + { + enabled: true, + name: 'Türkçe', + tag: 'tr', + }, + { + enabled: false, + name: 'Українська', + tag: 'uk', + }, + { + enabled: false, + name: 'Tiếng Việt', + tag: 'vi', + }, + { + enabled: true, + name: '简体中文', + tag: 'zh-CN', + }, + { + enabled: false, + name: '繁體中文', + tag: 'zh-TW', + }, +]; +module.exports = languages; diff --git a/test/load/__fixtures__/translated-site/siteConfig.js b/test/load/__fixtures__/translated-site/siteConfig.js new file mode 100644 index 0000000000..e64b9989cf --- /dev/null +++ b/test/load/__fixtures__/translated-site/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/load/__fixtures__/transversioned-site/languages.js b/test/load/__fixtures__/transversioned-site/languages.js new file mode 100644 index 0000000000..14c4aca911 --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/languages.js @@ -0,0 +1,178 @@ +const languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + { + enabled: false, + name: '日本語', + tag: 'ja', + }, + { + enabled: false, + name: 'العربية', + tag: 'ar', + }, + { + enabled: false, + name: 'Bosanski', + tag: 'bs-BA', + }, + { + enabled: false, + name: 'Català', + tag: 'ca', + }, + { + enabled: false, + name: 'Čeština', + tag: 'cs', + }, + { + enabled: false, + name: 'Dansk', + tag: 'da', + }, + { + enabled: false, + name: 'Deutsch', + tag: 'de', + }, + { + enabled: false, + name: 'Ελληνικά', + tag: 'el', + }, + { + enabled: true, + name: 'Español', + tag: 'es-ES', + }, + { + enabled: false, + name: 'فارسی', + tag: 'fa-IR', + }, + { + enabled: false, + name: 'Suomi', + tag: 'fi', + }, + { + enabled: false, + name: 'Français', + tag: 'fr', + }, + { + enabled: false, + name: 'עִברִית', + tag: 'he', + }, + { + enabled: false, + name: 'Magyar', + tag: 'hu', + }, + { + enabled: false, + name: 'Bahasa Indonesia', + tag: 'id-ID', + }, + { + enabled: false, + name: 'Italiano', + tag: 'it', + }, + { + enabled: false, + name: 'Afrikaans', + tag: 'af', + }, + { + enabled: false, + name: '한국어', + tag: 'ko', + }, + { + enabled: false, + name: 'मराठी', + tag: 'mr-IN', + }, + { + enabled: false, + name: 'Nederlands', + tag: 'nl', + }, + { + enabled: false, + name: 'Norsk', + tag: 'no-NO', + }, + { + enabled: false, + name: 'Polskie', + tag: 'pl', + }, + { + enabled: false, + name: 'Português', + tag: 'pt-PT', + }, + { + enabled: false, + name: 'Português (Brasil)', + tag: 'pt-BR', + }, + { + enabled: true, + name: 'Română', + tag: 'ro', + }, + { + enabled: false, + name: 'Русский', + tag: 'ru', + }, + { + enabled: false, + name: 'Slovenský', + tag: 'sk-SK', + }, + { + enabled: false, + name: 'Српски језик (Ћирилица)', + tag: 'sr', + }, + { + enabled: false, + name: 'Svenska', + tag: 'sv-SE', + }, + { + enabled: true, + name: 'Türkçe', + tag: 'tr', + }, + { + enabled: false, + name: 'Українська', + tag: 'uk', + }, + { + enabled: false, + name: 'Tiếng Việt', + tag: 'vi', + }, + { + enabled: true, + name: '简体中文', + tag: 'zh-CN', + }, + { + enabled: false, + name: '繁體中文', + tag: 'zh-TW', + }, +]; +module.exports = languages; diff --git a/test/load/__fixtures__/transversioned-site/siteConfig.js b/test/load/__fixtures__/transversioned-site/siteConfig.js new file mode 100644 index 0000000000..e64b9989cf --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/load/__fixtures__/transversioned-site/versions.json b/test/load/__fixtures__/transversioned-site/versions.json new file mode 100644 index 0000000000..542b187dfe --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/versions.json @@ -0,0 +1,4 @@ +[ + "1.0.1", + "1.0.0" +] diff --git a/test/load/__fixtures__/versioned-site/siteConfig.js b/test/load/__fixtures__/versioned-site/siteConfig.js new file mode 100644 index 0000000000..e64b9989cf --- /dev/null +++ b/test/load/__fixtures__/versioned-site/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/load/__fixtures__/versioned-site/versions.json b/test/load/__fixtures__/versioned-site/versions.json new file mode 100644 index 0000000000..542b187dfe --- /dev/null +++ b/test/load/__fixtures__/versioned-site/versions.json @@ -0,0 +1,4 @@ +[ + "1.0.1", + "1.0.0" +] diff --git a/test/load/__snapshots__/env.test.js.snap b/test/load/__snapshots__/env.test.js.snap new file mode 100644 index 0000000000..a5dd432d95 --- /dev/null +++ b/test/load/__snapshots__/env.test.js.snap @@ -0,0 +1,119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadEnv website with both versioning & translation disabled 1`] = ` +Object { + "translation": Object { + "enabled": false, + "enabledLanguages": Array [], + }, + "versioning": Object { + "defaultVersion": null, + "enabled": false, + "latestVersion": null, + "versions": Array [], + }, +} +`; + +exports[`loadEnv website with translation enabled 1`] = ` +Object { + "translation": Object { + "enabled": true, + "enabledLanguages": Array [ + Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + Object { + "enabled": true, + "name": "Español", + "tag": "es-ES", + }, + Object { + "enabled": true, + "name": "Română", + "tag": "ro", + }, + Object { + "enabled": true, + "name": "Türkçe", + "tag": "tr", + }, + Object { + "enabled": true, + "name": "简体中文", + "tag": "zh-CN", + }, + ], + }, + "versioning": Object { + "defaultVersion": null, + "enabled": false, + "latestVersion": null, + "versions": Array [], + }, +} +`; + +exports[`loadEnv website with versioning & translation enabled 1`] = ` +Object { + "translation": Object { + "enabled": true, + "enabledLanguages": Array [ + Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + Object { + "enabled": true, + "name": "Español", + "tag": "es-ES", + }, + Object { + "enabled": true, + "name": "Română", + "tag": "ro", + }, + Object { + "enabled": true, + "name": "Türkçe", + "tag": "tr", + }, + Object { + "enabled": true, + "name": "简体中文", + "tag": "zh-CN", + }, + ], + }, + "versioning": Object { + "defaultVersion": "1.0.1", + "enabled": true, + "latestVersion": "1.0.1", + "versions": Array [ + "1.0.1", + "1.0.0", + ], + }, +} +`; + +exports[`loadEnv website with versioning enabled 1`] = ` +Object { + "translation": Object { + "enabled": false, + "enabledLanguages": Array [], + }, + "versioning": Object { + "defaultVersion": "1.0.1", + "enabled": true, + "latestVersion": "1.0.1", + "versions": Array [ + "1.0.1", + "1.0.0", + ], + }, +} +`; diff --git a/test/load/__snapshots__/pages.test.js.snap b/test/load/__snapshots__/pages.test.js.snap index 8fcb8818fc..b52b89dd70 100644 --- a/test/load/__snapshots__/pages.test.js.snap +++ b/test/load/__snapshots__/pages.test.js.snap @@ -2,14 +2,14 @@ exports[`loadPages valid pages 1`] = ` Array [ - Object { - "path": "/foo", - "source": "foo.js", - }, Object { "path": "/", "source": "index.js", }, + Object { + "path": "/foo", + "source": "foo.js", + }, Object { "path": "/bar/baz", "source": "bar/baz.js", diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap index f03e3e2ec6..c9c8cbad84 100644 --- a/test/load/__snapshots__/routes.test.js.snap +++ b/test/load/__snapshots__/routes.test.js.snap @@ -36,10 +36,10 @@ const routes = [ }) }, { - path: \\"/foo/bar\\", + path: \\"/foo/baz\\", exact: true, component: Loadable({ - loader: () => import('@docs/foo/bar.md'), + loader: () => import('@docs/foo/baz.md'), loading: Loading, render(loaded, props) { let Content = loaded.default; @@ -48,10 +48,10 @@ const routes = [ }) }, { - path: \\"/foo/baz\\", + path: \\"/foo/bar\\", exact: true, component: Loadable({ - loader: () => import('@docs/foo/baz.md'), + loader: () => import('@docs/foo/bar.md'), loading: Loading, render(loaded, props) { let Content = loaded.default; @@ -159,14 +159,6 @@ const routes = [ } }) }, - { - path: \\"/foo\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/foo.js'), - loading: Loading - }) - }, { path: \\"/\\", exact: true, @@ -176,10 +168,10 @@ const routes = [ }) }, { - path: \\"/bar/baz\\", + path: \\"/foo\\", exact: true, component: Loadable({ - loader: () => import('@pages/bar/baz.js'), + loader: () => import('@pages/foo.js'), loading: Loading }) }, @@ -191,6 +183,14 @@ const routes = [ loading: Loading }) }, + { + path: \\"/bar/baz\\", + exact: true, + component: Loadable({ + loader: () => import('@pages/bar/baz.js'), + loading: Loading + }) + }, { path: '*', component: NotFound diff --git a/test/load/env.test.js b/test/load/env.test.js new file mode 100644 index 0000000000..577ddb86d8 --- /dev/null +++ b/test/load/env.test.js @@ -0,0 +1,41 @@ +import path from 'path'; +import loadEnv from '@lib/load/env'; +import loadConfig from '@lib/load/config'; + +describe('loadEnv', () => { + test('website with both versioning & translation disabled', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); + const siteConfig = loadConfig(siteDir); + const env = loadEnv({siteDir, siteConfig}); + expect(env.versioning.enabled).toBe(false); + expect(env.translation.enabled).toBe(false); + expect(env).toMatchSnapshot(); + }); + + test('website with versioning enabled', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site'); + const siteConfig = loadConfig(siteDir); + const env = loadEnv({siteDir, siteConfig}); + expect(env.versioning.enabled).toBe(true); + expect(env.translation.enabled).toBe(false); + expect(env).toMatchSnapshot(); + }); + + test('website with translation enabled', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'translated-site'); + const siteConfig = loadConfig(siteDir); + const env = loadEnv({siteDir, siteConfig}); + expect(env.versioning.enabled).toBe(false); + expect(env.translation.enabled).toBe(true); + expect(env).toMatchSnapshot(); + }); + + test('website with versioning & translation enabled', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'transversioned-site'); + const siteConfig = loadConfig(siteDir); + const env = loadEnv({siteDir, siteConfig}); + expect(env.versioning.enabled).toBe(true); + expect(env.translation.enabled).toBe(true); + expect(env).toMatchSnapshot(); + }); +}); From d00864d222a64a8115452768fa94b836e2e7b41c Mon Sep 17 00:00:00 2001 From: endiliey Date: Thu, 6 Sep 2018 21:33:50 +0800 Subject: [PATCH 104/135] feat: add @theme/Markdown to allow user modify their own markdown react component --- lib/load/theme.js | 2 +- lib/theme/Docs/index.js | 17 ---------- .../components => theme}/Markdown/anchors.js | 0 .../Markdown/highlight.js | 0 .../components => theme}/Markdown/index.js | 32 +++++++++++++++---- .../components => theme}/Markdown/toSlug.js | 0 lib/theme/NotFound.js | 5 ++- lib/webpack/loader/markdown.js | 15 ++++++--- 8 files changed, 41 insertions(+), 30 deletions(-) rename lib/{core/components => theme}/Markdown/anchors.js (100%) rename lib/{core/components => theme}/Markdown/highlight.js (100%) rename lib/{core/components => theme}/Markdown/index.js (68%) rename lib/{core/components => theme}/Markdown/toSlug.js (100%) diff --git a/lib/load/theme.js b/lib/load/theme.js index 0aa529c145..a4643feb5c 100644 --- a/lib/load/theme.js +++ b/lib/load/theme.js @@ -7,7 +7,7 @@ module.exports = function loadConfig(siteDir) { ? customThemePath : path.resolve(__dirname, '../theme'); - const themeComponents = ['Docs', 'Loading', 'NotFound']; + const themeComponents = ['Docs', 'Loading', 'NotFound', 'Markdown']; themeComponents.forEach(component => { if (!require.resolve(path.join(themePath, component))) { throw new Error( diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index e4e1d0862f..910684ead6 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -9,27 +9,10 @@ export default class Docs extends React.Component { const {route, docsData, siteConfig} = this.props; const currentDoc = docsData.find(data => data.path === route.path); - const highlight = Object.assign( - {}, - { - version: '9.12.0', - theme: 'default' - }, - siteConfig.highlight - ); - - // Use user-provided themeUrl if it exists, else construct one from version and theme. - const highlightThemeURL = highlight.themeUrl - ? highlight.themeUrl - : `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${ - highlight.version - }/styles/${highlight.theme}.min.css`; - return ( {(currentDoc && currentDoc.title) || siteConfig.title} -
    {this.props.children}
    diff --git a/lib/core/components/Markdown/anchors.js b/lib/theme/Markdown/anchors.js similarity index 100% rename from lib/core/components/Markdown/anchors.js rename to lib/theme/Markdown/anchors.js diff --git a/lib/core/components/Markdown/highlight.js b/lib/theme/Markdown/highlight.js similarity index 100% rename from lib/core/components/Markdown/highlight.js rename to lib/theme/Markdown/highlight.js diff --git a/lib/core/components/Markdown/index.js b/lib/theme/Markdown/index.js similarity index 68% rename from lib/core/components/Markdown/index.js rename to lib/theme/Markdown/index.js index c9412efc8d..6eb0a378d1 100644 --- a/lib/core/components/Markdown/index.js +++ b/lib/theme/Markdown/index.js @@ -2,6 +2,7 @@ import React from 'react'; import Markdown from 'remarkable'; +import Helmet from 'react-helmet'; import highlight from './highlight'; import anchors from './anchors'; @@ -58,16 +59,35 @@ class MarkdownBlock extends React.Component { } render() { - const Container = this.props.container; - if (!Container) { - return
    {this.content()}
    ; - } - return {this.content()}; + const {siteConfig} = this.props; + const highlight = Object.assign( + {}, + { + version: '9.12.0', + theme: 'default' + }, + siteConfig.highlight + ); + + // Use user-provided themeUrl if it exists, else construct one from version and theme. + const highlightThemeURL = highlight.themeUrl + ? highlight.themeUrl + : `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${ + highlight.version + }/styles/${highlight.theme}.min.css`; + + return ( +
    + + + + {this.content()} +
    + ); } } MarkdownBlock.defaultProps = { - container: 'div', siteConfig: {} }; diff --git a/lib/core/components/Markdown/toSlug.js b/lib/theme/Markdown/toSlug.js similarity index 100% rename from lib/core/components/Markdown/toSlug.js rename to lib/theme/Markdown/toSlug.js diff --git a/lib/theme/NotFound.js b/lib/theme/NotFound.js index 74abb1c7e7..193b0edb29 100644 --- a/lib/theme/NotFound.js +++ b/lib/theme/NotFound.js @@ -7,7 +7,10 @@ export default class NotFound extends React.Component {
    404 Page Not Found
    - Not found + Not found
    ); diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index d4a14e6310..c11f3f671f 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -5,14 +5,19 @@ module.exports = function(fileString) { const options = getOptions(this); const {body} = fm(fileString); - const source = JSON.stringify(body); + + const content = JSON.stringify(body); + // TODO replace all the markdown linking to correct url depends on whether it's versioned/translated/normal docs + // e.g: [test](test.md) become [test](/docs/test) const siteConfig = JSON.stringify(options.siteConfig); return ( `import React from 'react';\n` + - `import MarkdownBlock from '@core/components/Markdown'\n` + - `export default () => ;` + `import Markdown from '@theme/Markdown'\n` + + `export default () => ( + + {${content}} + + );` ); - - // return `export default () => `; }; From 988232edd4a4246226b6dfe617c4072588039ee6 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 13:51:01 +0800 Subject: [PATCH 105/135] wip: trans & versioning --- lib/load/config.js | 1 + lib/load/env.js | 26 ++- test/load/__fixtures__/bad-site/languages.js | 178 ++++++++++++++++++ .../__fixtures__/simple-site/sidebars.json | 10 + .../translated-site/siteConfig.js | 3 +- .../transversioned-site/sidebars.json | 10 + .../transversioned-site/siteConfig.js | 3 +- .../version-1.0.0-sidebars.json | 10 + .../version-1.0.1-sidebars.json | 10 + .../__fixtures__/versioned-site/sidebars.json | 10 + .../version-1.0.0-sidebars.json | 10 + .../version-1.0.1-sidebars.json | 10 + test/load/__snapshots__/env.test.js.snap | 12 ++ test/load/env.test.js | 67 ++++++- 14 files changed, 350 insertions(+), 10 deletions(-) create mode 100644 test/load/__fixtures__/bad-site/languages.js create mode 100644 test/load/__fixtures__/simple-site/sidebars.json create mode 100644 test/load/__fixtures__/transversioned-site/sidebars.json create mode 100644 test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json create mode 100644 test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json create mode 100644 test/load/__fixtures__/versioned-site/sidebars.json create mode 100644 test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json create mode 100644 test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json diff --git a/lib/load/config.js b/lib/load/config.js index fd325ce08f..618189db89 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -20,6 +20,7 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { ]; const optionalFields = [ 'customDocsPath', + 'defaultLanguage', 'highlight', 'markdownPlugins', 'configureWebpack', diff --git a/lib/load/env.js b/lib/load/env.js index d53b46f416..acb40f4b1d 100644 --- a/lib/load/env.js +++ b/lib/load/env.js @@ -5,14 +5,34 @@ module.exports = function loadEnv({siteDir, siteConfig}) { // Translation const translation = { enabled: false, - enabledLanguages: [] + enabledLanguages: [], + defaultLanguage: {} }; const languagesFile = path.join(siteDir, 'languages.js'); if (fs.existsSync(languagesFile)) { - translation.enabled = true; const languages = require(languagesFile); - translation.enabledLanguages = languages.filter(lang => lang.enabled); + + /* Enabled languages */ + const enabledLanguages = languages.filter(lang => lang.enabled); + if (!enabledLanguages || enabledLanguages.length === 0) { + throw new Error(`Please at least enable one language in 'languages.js'`); + } + translation.enabledLanguages = enabledLanguages; + + /* Default Language */ + const {defaultLanguage: defaultLanguageTag} = siteConfig; + const defaultLanguage = enabledLanguages.find( + lang => lang.tag === defaultLanguageTag + ); + if (!defaultLanguage) { + throw new Error( + `Please set a default language in 'siteConfig.js' which is enabled in 'languages.js'` + ); + } + translation.defaultLanguage = defaultLanguage; + + translation.enabled = true; } // Versioning diff --git a/test/load/__fixtures__/bad-site/languages.js b/test/load/__fixtures__/bad-site/languages.js new file mode 100644 index 0000000000..fb5033422d --- /dev/null +++ b/test/load/__fixtures__/bad-site/languages.js @@ -0,0 +1,178 @@ +const languages = [ + { + enabled: false, + name: 'English', + tag: 'en', + }, + { + enabled: false, + name: '日本語', + tag: 'ja', + }, + { + enabled: false, + name: 'العربية', + tag: 'ar', + }, + { + enabled: false, + name: 'Bosanski', + tag: 'bs-BA', + }, + { + enabled: false, + name: 'Català', + tag: 'ca', + }, + { + enabled: false, + name: 'Čeština', + tag: 'cs', + }, + { + enabled: false, + name: 'Dansk', + tag: 'da', + }, + { + enabled: false, + name: 'Deutsch', + tag: 'de', + }, + { + enabled: false, + name: 'Ελληνικά', + tag: 'el', + }, + { + enabled: false, + name: 'Español', + tag: 'es-ES', + }, + { + enabled: false, + name: 'فارسی', + tag: 'fa-IR', + }, + { + enabled: false, + name: 'Suomi', + tag: 'fi', + }, + { + enabled: false, + name: 'Français', + tag: 'fr', + }, + { + enabled: false, + name: 'עִברִית', + tag: 'he', + }, + { + enabled: false, + name: 'Magyar', + tag: 'hu', + }, + { + enabled: false, + name: 'Bahasa Indonesia', + tag: 'id-ID', + }, + { + enabled: false, + name: 'Italiano', + tag: 'it', + }, + { + enabled: false, + name: 'Afrikaans', + tag: 'af', + }, + { + enabled: false, + name: '한국어', + tag: 'ko', + }, + { + enabled: false, + name: 'मराठी', + tag: 'mr-IN', + }, + { + enabled: false, + name: 'Nederlands', + tag: 'nl', + }, + { + enabled: false, + name: 'Norsk', + tag: 'no-NO', + }, + { + enabled: false, + name: 'Polskie', + tag: 'pl', + }, + { + enabled: false, + name: 'Português', + tag: 'pt-PT', + }, + { + enabled: false, + name: 'Português (Brasil)', + tag: 'pt-BR', + }, + { + enabled: false, + name: 'Română', + tag: 'ro', + }, + { + enabled: false, + name: 'Русский', + tag: 'ru', + }, + { + enabled: false, + name: 'Slovenský', + tag: 'sk-SK', + }, + { + enabled: false, + name: 'Српски језик (Ћирилица)', + tag: 'sr', + }, + { + enabled: false, + name: 'Svenska', + tag: 'sv-SE', + }, + { + enabled: false, + name: 'Türkçe', + tag: 'tr', + }, + { + enabled: false, + name: 'Українська', + tag: 'uk', + }, + { + enabled: false, + name: 'Tiếng Việt', + tag: 'vi', + }, + { + enabled: false, + name: '简体中文', + tag: 'zh-CN', + }, + { + enabled: false, + name: '繁體中文', + tag: 'zh-TW', + }, +]; +module.exports = languages; diff --git a/test/load/__fixtures__/simple-site/sidebars.json b/test/load/__fixtures__/simple-site/sidebars.json new file mode 100644 index 0000000000..49667e47b5 --- /dev/null +++ b/test/load/__fixtures__/simple-site/sidebars.json @@ -0,0 +1,10 @@ +{ + "docs": { + "Getting Started": [ + "installation" + ], + "Guides": [ + "blog" + ] + } +} diff --git a/test/load/__fixtures__/translated-site/siteConfig.js b/test/load/__fixtures__/translated-site/siteConfig.js index e64b9989cf..661f59c981 100644 --- a/test/load/__fixtures__/translated-site/siteConfig.js +++ b/test/load/__fixtures__/translated-site/siteConfig.js @@ -3,5 +3,6 @@ module.exports = { tagline: 'Hello World', organizationName: 'endiliey', projectName: 'hello', - baseUrl: '/' + baseUrl: '/', + defaultLanguage: 'en' }; diff --git a/test/load/__fixtures__/transversioned-site/sidebars.json b/test/load/__fixtures__/transversioned-site/sidebars.json new file mode 100644 index 0000000000..49667e47b5 --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/sidebars.json @@ -0,0 +1,10 @@ +{ + "docs": { + "Getting Started": [ + "installation" + ], + "Guides": [ + "blog" + ] + } +} diff --git a/test/load/__fixtures__/transversioned-site/siteConfig.js b/test/load/__fixtures__/transversioned-site/siteConfig.js index e64b9989cf..661f59c981 100644 --- a/test/load/__fixtures__/transversioned-site/siteConfig.js +++ b/test/load/__fixtures__/transversioned-site/siteConfig.js @@ -3,5 +3,6 @@ module.exports = { tagline: 'Hello World', organizationName: 'endiliey', projectName: 'hello', - baseUrl: '/' + baseUrl: '/', + defaultLanguage: 'en' }; diff --git a/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000000..7769c0cf64 --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,10 @@ +{ + "version-1.0.0-docs": { + "Getting Started": [ + "version-1.0.0-installation" + ], + "Guides": [ + "version-1.0.0-blog" + ] + } +} diff --git a/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json new file mode 100644 index 0000000000..386bfae67e --- /dev/null +++ b/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json @@ -0,0 +1,10 @@ +{ + "version-1.0.1-docs": { + "Getting Started": [ + "version-1.0.1-installation" + ], + "Guides": [ + "version-1.0.1-blog" + ] + } +} diff --git a/test/load/__fixtures__/versioned-site/sidebars.json b/test/load/__fixtures__/versioned-site/sidebars.json new file mode 100644 index 0000000000..49667e47b5 --- /dev/null +++ b/test/load/__fixtures__/versioned-site/sidebars.json @@ -0,0 +1,10 @@ +{ + "docs": { + "Getting Started": [ + "installation" + ], + "Guides": [ + "blog" + ] + } +} diff --git a/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000000..7769c0cf64 --- /dev/null +++ b/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,10 @@ +{ + "version-1.0.0-docs": { + "Getting Started": [ + "version-1.0.0-installation" + ], + "Guides": [ + "version-1.0.0-blog" + ] + } +} diff --git a/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json new file mode 100644 index 0000000000..386bfae67e --- /dev/null +++ b/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json @@ -0,0 +1,10 @@ +{ + "version-1.0.1-docs": { + "Getting Started": [ + "version-1.0.1-installation" + ], + "Guides": [ + "version-1.0.1-blog" + ] + } +} diff --git a/test/load/__snapshots__/env.test.js.snap b/test/load/__snapshots__/env.test.js.snap index a5dd432d95..cdc1ab6207 100644 --- a/test/load/__snapshots__/env.test.js.snap +++ b/test/load/__snapshots__/env.test.js.snap @@ -3,6 +3,7 @@ exports[`loadEnv website with both versioning & translation disabled 1`] = ` Object { "translation": Object { + "defaultLanguage": Object {}, "enabled": false, "enabledLanguages": Array [], }, @@ -18,6 +19,11 @@ Object { exports[`loadEnv website with translation enabled 1`] = ` Object { "translation": Object { + "defaultLanguage": Object { + "enabled": true, + "name": "English", + "tag": "en", + }, "enabled": true, "enabledLanguages": Array [ Object { @@ -59,6 +65,11 @@ Object { exports[`loadEnv website with versioning & translation enabled 1`] = ` Object { "translation": Object { + "defaultLanguage": Object { + "enabled": true, + "name": "English", + "tag": "en", + }, "enabled": true, "enabledLanguages": Array [ Object { @@ -103,6 +114,7 @@ Object { exports[`loadEnv website with versioning enabled 1`] = ` Object { "translation": Object { + "defaultLanguage": Object {}, "enabled": false, "enabledLanguages": Array [], }, diff --git a/test/load/env.test.js b/test/load/env.test.js index 577ddb86d8..7724bf9186 100644 --- a/test/load/env.test.js +++ b/test/load/env.test.js @@ -1,11 +1,16 @@ import path from 'path'; import loadEnv from '@lib/load/env'; -import loadConfig from '@lib/load/config'; describe('loadEnv', () => { test('website with both versioning & translation disabled', () => { const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); - const siteConfig = loadConfig(siteDir); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }; const env = loadEnv({siteDir, siteConfig}); expect(env.versioning.enabled).toBe(false); expect(env.translation.enabled).toBe(false); @@ -14,7 +19,13 @@ describe('loadEnv', () => { test('website with versioning enabled', () => { const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site'); - const siteConfig = loadConfig(siteDir); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }; const env = loadEnv({siteDir, siteConfig}); expect(env.versioning.enabled).toBe(true); expect(env.translation.enabled).toBe(false); @@ -23,7 +34,14 @@ describe('loadEnv', () => { test('website with translation enabled', () => { const siteDir = path.join(__dirname, '__fixtures__', 'translated-site'); - const siteConfig = loadConfig(siteDir); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello', + defaultLanguage: 'en' + }; const env = loadEnv({siteDir, siteConfig}); expect(env.versioning.enabled).toBe(false); expect(env.translation.enabled).toBe(true); @@ -32,10 +50,49 @@ describe('loadEnv', () => { test('website with versioning & translation enabled', () => { const siteDir = path.join(__dirname, '__fixtures__', 'transversioned-site'); - const siteConfig = loadConfig(siteDir); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello', + defaultLanguage: 'en' + }; const env = loadEnv({siteDir, siteConfig}); expect(env.versioning.enabled).toBe(true); expect(env.translation.enabled).toBe(true); expect(env).toMatchSnapshot(); }); + + test('website with languages.js but no lang is enabled', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'bad-site'); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }; + expect(() => { + loadEnv({siteDir, siteConfig}); + }).toThrowErrorMatchingInlineSnapshot( + `"Please at least enable one language in 'languages.js'"` + ); + }); + + test('website with languages.js but no default language set', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'translated-site'); + const siteConfig = { + baseUrl: '/', + organizationName: 'endiliey', + projectName: 'hello', + tagline: 'Hello World', + title: 'Hello' + }; + expect(() => { + loadEnv({siteDir, siteConfig}); + }).toThrowErrorMatchingInlineSnapshot( + `"Please set a default language in 'siteConfig.js' which is enabled in 'languages.js'"` + ); + }); }); From 2141e6ea90594b7602f0fbc73d1afe0f50459584 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 13:53:14 +0800 Subject: [PATCH 106/135] test: loadPages --- test/load/__snapshots__/docs.test.js.snap | 24 ---------------------- test/load/__snapshots__/pages.test.js.snap | 12 +++++------ test/load/pages.test.js | 6 +++++- 3 files changed, 11 insertions(+), 31 deletions(-) delete mode 100644 test/load/__snapshots__/docs.test.js.snap diff --git a/test/load/__snapshots__/docs.test.js.snap b/test/load/__snapshots__/docs.test.js.snap deleted file mode 100644 index 8c07385f96..0000000000 --- a/test/load/__snapshots__/docs.test.js.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loadDocs simple docs 1`] = ` -Array [ - Object { - "id": "hello", - "path": "/hello", - "source": "hello.md", - "title": "Hello, World !", - }, - Object { - "id": "bar", - "path": "/foo/bar", - "source": "foo/bar.md", - "title": "Bar", - }, - Object { - "id": "baz", - "path": "/foo/baz", - "source": "foo/baz.md", - "title": "baz", - }, -] -`; diff --git a/test/load/__snapshots__/pages.test.js.snap b/test/load/__snapshots__/pages.test.js.snap index b52b89dd70..daa058daba 100644 --- a/test/load/__snapshots__/pages.test.js.snap +++ b/test/load/__snapshots__/pages.test.js.snap @@ -2,21 +2,21 @@ exports[`loadPages valid pages 1`] = ` Array [ - Object { - "path": "/", - "source": "index.js", - }, Object { "path": "/foo", "source": "foo.js", }, Object { - "path": "/bar/baz", - "source": "bar/baz.js", + "path": "/", + "source": "index.js", }, Object { "path": "/foo/", "source": "foo/index.js", }, + Object { + "path": "/bar/baz", + "source": "bar/baz.js", + }, ] `; diff --git a/test/load/pages.test.js b/test/load/pages.test.js index 7a76e76a82..b00d554924 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -3,7 +3,11 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { - const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); + const pagesDir = path.join( + __dirname, + '__fixtures__', + 'simple-pages' + ); const pagesData = await loadPages(pagesDir); expect(pagesData).toMatchSnapshot(); expect(pagesData).not.toBeNull(); From b477863a30f76e8baf0fdef3648ed9b7a47f189f Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 13:59:17 +0800 Subject: [PATCH 107/135] chore: prepare for docs sidebar --- lib/load/docs/order.js | 34 ++++++++++ lib/load/docs/sidebars.js | 34 ++++++++++ lib/load/utils.js | 35 ++++++++++- package.json | 1 + .../docs/__snapshots__/order.test.js.snap | 59 +++++++++++++++++ .../docs/__snapshots__/sidebars.test.js.snap | 45 +++++++++++++ test/load/docs/order.test.js | 35 +++++++++++ test/load/docs/sidebars.test.js | 46 ++++++++++++++ test/load/utils.test.js | 63 ++++++++++++++++++- 9 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 lib/load/docs/order.js create mode 100644 lib/load/docs/sidebars.js create mode 100644 test/load/docs/__snapshots__/order.test.js.snap create mode 100644 test/load/docs/__snapshots__/sidebars.test.js.snap create mode 100644 test/load/docs/order.test.js create mode 100644 test/load/docs/sidebars.test.js diff --git a/lib/load/docs/order.js b/lib/load/docs/order.js new file mode 100644 index 0000000000..9d69798e08 --- /dev/null +++ b/lib/load/docs/order.js @@ -0,0 +1,34 @@ +// build the docs meta such as next, previous, category and sidebar +module.exports = function createOrder(allSidebars = {}) { + const order = {}; + if (!allSidebars) { + return order; + } + Object.keys(allSidebars).forEach(sidebar => { + const categories = allSidebars[sidebar]; + + let ids = []; + const categoryOrder = []; + Object.keys(categories).forEach(category => { + ids = ids.concat(categories[category]); + for (let i = 0; i < categories[category].length; i++) { + categoryOrder.push(category); + } + }); + + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + let previous; + let next; + if (i > 0) previous = ids[i - 1]; + if (i < ids.length - 1) next = ids[i + 1]; + order[id] = { + previous, + next, + sidebar, + category: categoryOrder[i] + }; + } + }); + return order; +}; diff --git a/lib/load/docs/sidebars.js b/lib/load/docs/sidebars.js new file mode 100644 index 0000000000..92b0e16553 --- /dev/null +++ b/lib/load/docs/sidebars.js @@ -0,0 +1,34 @@ +const fs = require('fs-extra'); +const path = require('path'); +const {idx} = require('../utils'); + +module.exports = function loadSidebars({siteDir, env}) { + let allSidebars = {}; + + // current sidebars + const sidebarsJSONFile = path.join(siteDir, 'sidebars.json'); + if (fs.existsSync(sidebarsJSONFile)) { + allSidebars = require(sidebarsJSONFile); + } + + // versioned sidebars + if (idx(env, ['versioning', 'enabled'])) { + const versions = idx(env, ['versioning', 'versions']); + versions && + versions.forEach(version => { + const versionedSidebarsJSONFile = path.join( + siteDir, + 'versioned_sidebars', + `version-${version}-sidebars.json` + ); + if (fs.existsSync(versionedSidebarsJSONFile)) { + const sidebar = require(versionedSidebarsJSONFile); + Object.assign(allSidebars, sidebar); + } else { + const missingFile = path.relative(siteDir, versionedSidebarsJSONFile); + throw new Error(`Failed to load ${missingFile}. It does not exist.`); + } + }); + } + return allSidebars; +}; diff --git a/lib/load/utils.js b/lib/load/utils.js index 05be648bb2..060bcea9ac 100644 --- a/lib/load/utils.js +++ b/lib/load/utils.js @@ -1,4 +1,6 @@ const path = require('path'); +const fm = require('front-matter'); +const escapeStringRegexp = require('escape-string-regexp'); const fs = require('fs-extra'); const genPath = path.resolve(__dirname, '../core/generated'); @@ -40,9 +42,40 @@ function fileToComponentName(file) { return ext ? ext.toUpperCase() + str : str; } +function idx(target, keyPaths) { + return ( + target && + (Array.isArray(keyPaths) + ? keyPaths.reduce((obj, key) => obj && obj[key], target) + : target[keyPaths]) + ); +} + +function getSubFolder(file, refDir) { + const separator = escapeStringRegexp(path.sep); + const baseDir = escapeStringRegexp(path.basename(refDir)); + const regexSubFolder = new RegExp( + `${baseDir}${separator}(.*?)${separator}.*` + ); + const match = regexSubFolder.exec(file); + return match && match[1]; +} + +function parse(fileString) { + if (!fm.test(fileString)) { + return {metadata: null, content: fileString}; + } + const {attributes: metadata, body: content} = fm(fileString); + + return {metadata, content}; +} + module.exports = { encodePath, generate, fileToPath, - fileToComponentName + fileToComponentName, + getSubFolder, + idx, + parse }; diff --git a/package.json b/package.json index 5502c30878..b4f92d377e 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "connect-history-api-fallback": "^1.5.0", "css-loader": "^1.0.0", "escape-html": "^1.0.3", + "escape-string-regexp": "^1.0.5", "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", diff --git a/test/load/docs/__snapshots__/order.test.js.snap b/test/load/docs/__snapshots__/order.test.js.snap new file mode 100644 index 0000000000..11fb9ace9d --- /dev/null +++ b/test/load/docs/__snapshots__/order.test.js.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`createOrder should populate docs index from multiple sidebars 1`] = ` +Object { + "doc1": Object { + "category": "Category1", + "next": "doc2", + "previous": undefined, + "sidebar": "docs", + }, + "doc2": Object { + "category": "Category1", + "next": "doc3", + "previous": "doc1", + "sidebar": "docs", + }, + "doc3": Object { + "category": "Category2", + "next": "doc4", + "previous": "doc2", + "sidebar": "docs", + }, + "doc4": Object { + "category": "Category2", + "next": undefined, + "previous": "doc3", + "sidebar": "docs", + }, + "doc5": Object { + "category": "Category1", + "next": undefined, + "previous": undefined, + "sidebar": "otherDocs", + }, +} +`; + +exports[`createOrder should resolve docs from older versions 1`] = ` +Object { + "doc1": Object { + "category": "Category1", + "next": undefined, + "previous": undefined, + "sidebar": "docs", + }, + "version-1.2.3-doc1": Object { + "category": "Category2", + "next": undefined, + "previous": "version-1.2.3-doc2", + "sidebar": "version-1.2.3-docs", + }, + "version-1.2.3-doc2": Object { + "category": "Category1", + "next": "version-1.2.3-doc1", + "previous": undefined, + "sidebar": "version-1.2.3-docs", + }, +} +`; diff --git a/test/load/docs/__snapshots__/sidebars.test.js.snap b/test/load/docs/__snapshots__/sidebars.test.js.snap new file mode 100644 index 0000000000..e96f753e75 --- /dev/null +++ b/test/load/docs/__snapshots__/sidebars.test.js.snap @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadSidebars normal site with sidebars 1`] = ` +Object { + "docs": Object { + "Getting Started": Array [ + "installation", + ], + "Guides": Array [ + "blog", + ], + }, +} +`; + +exports[`loadSidebars site with sidebars & versioned sidebars 1`] = ` +Object { + "docs": Object { + "Getting Started": Array [ + "installation", + ], + "Guides": Array [ + "blog", + ], + }, + "version-1.0.0-docs": Object { + "Getting Started": Array [ + "version-1.0.0-installation", + ], + "Guides": Array [ + "version-1.0.0-blog", + ], + }, + "version-1.0.1-docs": Object { + "Getting Started": Array [ + "version-1.0.1-installation", + ], + "Guides": Array [ + "version-1.0.1-blog", + ], + }, +} +`; + +exports[`loadSidebars site without sidebars 1`] = `Object {}`; diff --git a/test/load/docs/order.test.js b/test/load/docs/order.test.js new file mode 100644 index 0000000000..ef4d0f2b66 --- /dev/null +++ b/test/load/docs/order.test.js @@ -0,0 +1,35 @@ +import createOrder from '@lib/load/docs/order'; + +describe('createOrder', () => { + test('should populate docs index from multiple sidebars', () => { + const result = createOrder({ + docs: { + Category1: ['doc1', 'doc2'], + Category2: ['doc3', 'doc4'] + }, + otherDocs: { + Category1: ['doc5'] + } + }); + expect(result).toMatchSnapshot(); + }); + + test('should resolve docs from older versions', () => { + const result = createOrder({ + docs: { + Category1: ['doc1'] + }, + 'version-1.2.3-docs': { + Category1: ['version-1.2.3-doc2'], + Category2: ['version-1.2.3-doc1'] + } + }); + expect(result).toMatchSnapshot(); + }); + + test('edge cases', () => { + expect(createOrder({})).toEqual({}); + expect(createOrder(null)).toEqual({}); + expect(createOrder(undefined)).toEqual({}); + }); +}); diff --git a/test/load/docs/sidebars.test.js b/test/load/docs/sidebars.test.js new file mode 100644 index 0000000000..d5cb1411b8 --- /dev/null +++ b/test/load/docs/sidebars.test.js @@ -0,0 +1,46 @@ +import path from 'path'; +import loadSidebars from '@lib/load/docs/sidebars'; + +describe('loadSidebars', () => { + const fixtures = path.join(__dirname, '..', '__fixtures__'); + test('normal site with sidebars', () => { + const env = {}; + const siteDir = path.join(fixtures, 'simple-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site without sidebars', () => { + const env = {}; + const siteDir = path.join(fixtures, 'bad-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site with sidebars & versioned sidebars', () => { + const env = { + versioning: { + enabled: true, + versions: ['1.0.1', '1.0.0'] + } + }; + const siteDir = path.join(fixtures, 'versioned-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site with missing versioned sidebars', () => { + const env = { + versioning: { + enabled: true, + versions: ['2.0.0'] + } + }; + const siteDir = path.join(fixtures, 'versioned-site'); + expect(() => { + loadSidebars({siteDir, env}); + }).toThrowErrorMatchingInlineSnapshot( + `"Failed to load versioned_sidebars/version-2.0.0-sidebars.json. It does not exist."` + ); + }); +}); diff --git a/test/load/utils.test.js b/test/load/utils.test.js index 7012f191bd..bf9e54e463 100644 --- a/test/load/utils.test.js +++ b/test/load/utils.test.js @@ -1,4 +1,10 @@ -import {fileToPath, fileToComponentName} from '@lib/load/utils'; +import path from 'path'; +import { + fileToPath, + fileToComponentName, + idx, + getSubFolder +} from '@lib/load/utils'; describe('load utils', () => { test('fileToComponentName', () => { @@ -34,4 +40,59 @@ describe('load utils', () => { expect(fileToPath(file)).toBe(asserts[file]); }); }); + + test('idx', () => { + const a = {}; + const b = {hello: 'world'}; + const env = { + translation: { + enabled: true, + enabledLanguages: [ + { + enabled: true, + name: 'English', + tag: 'en' + }, + { + enabled: true, + name: '日本語', + tag: 'ja' + } + ] + }, + versioning: { + enabled: false, + versions: [] + } + }; + const variable = 'enabledLanguages'; + expect(idx(a, [('b', 'c')])).toBeUndefined(); + expect(idx(b, ['hello'])).toEqual('world'); + expect(idx(b, 'hello')).toEqual('world'); + expect(idx(env, 'typo')).toBeUndefined(); + expect(idx(env, 'versioning')).toEqual({ + enabled: false, + versions: [] + }); + expect(idx(env, ['translation', 'enabled'])).toEqual(true); + expect(idx(env, ['translation', variable]).map(lang => lang.tag)).toEqual([ + 'en', + 'ja' + ]); + expect(idx(undefined)).toBeUndefined(); + expect(idx(null)).toBeNull(); + }); + + test('getSubFolder', () => { + const testA = path.join('folder', 'en', 'test.md'); + const testB = path.join('folder', 'ja', 'test.md'); + const testC = path.join('folder', 'ja', 'en', 'test.md'); + const testD = path.join('docs', 'ro', 'test.md'); + const testE = path.join('docs', 'test.md'); + expect(getSubFolder(testA, 'folder')).toBe('en'); + expect(getSubFolder(testB, 'folder')).toBe('ja'); + expect(getSubFolder(testC, 'folder')).toBe('ja'); + expect(getSubFolder(testD, 'docs')).toBe('ro'); + expect(getSubFolder(testE, 'docs')).toBeNull(); + }); }); From 31d333b82f6f36a8ad042446b95eaf60a6af965d Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 18:00:50 +0800 Subject: [PATCH 108/135] test: add easy setup for test cases --- .../pages/bar/baz.js | 0 .../pages/foo.js | 0 .../pages/foo/index.js | 0 .../pages/index.js | 0 .../siteConfig.js | 0 test/__fixtures__/docs/foo/baz.md | 3 - .../simple-site/pages/hello/world.js | 17 + test/__fixtures__/simple-site/pages/index.js | 17 + test/__fixtures__/simple-site/sidebars.json | 10 + .../siteConfig.js | 0 .../simple-site/static/css/basic.css | 378 ++++++++++++++++++ .../simple-site/static/img/sakura.png | Bin 0 -> 79340 bytes .../static/img/slash-introducing.png | Bin 0 -> 15983 bytes .../simple-website/pages/bar/baz.js | 3 - test/__fixtures__/simple-website/pages/foo.js | 3 - .../simple-website/pages/foo/index.js | 3 - .../simple-website/pages/index.js | 3 - .../__fixtures__/translated-site/languages.js | 178 +++++++++ .../translated-site/pages/hello/world.js | 17 + .../translated-site/pages/index.js | 17 + .../translated-site/siteConfig.js | 8 + .../translated-site/static/css/basic.css | 378 ++++++++++++++++++ .../translated-site/static/img/sakura.png | Bin 0 -> 79340 bytes .../static/img/slash-introducing.png | Bin 0 -> 15983 bytes .../translated_docs/ko/docs/foo/bar.md | 66 +++ .../translated_docs/ko/docs/foo/baz.md | 74 ++++ .../translated_docs/ko/docs/hello.md | 40 ++ .../transversioned-site/languages.js | 178 +++++++++ .../transversioned-site/pages/hello/world.js | 17 + .../transversioned-site/pages/index.js | 17 + .../transversioned-site/sidebars.json | 11 + .../transversioned-site/siteConfig.js | 8 + .../transversioned-site/static/css/basic.css | 378 ++++++++++++++++++ .../transversioned-site/static/img/sakura.png | Bin 0 -> 79340 bytes .../static/img/slash-introducing.png | Bin 0 -> 15983 bytes .../ko/version-1.0.0/foo/bar.md | 66 +++ .../ko/version-1.0.0/foo/baz.md | 74 ++++ .../translated_docs/ko/version-1.0.0/hello.md | 40 ++ .../ko/version-1.0.1/foo/bar.md | 66 +++ .../ko/version-1.0.1/foo/baz.md | 74 ++++ .../translated_docs/ko/version-1.0.1/hello.md | 40 ++ .../versioned_docs/version-1.0.0/foo/bar.md | 66 +++ .../versioned_docs/version-1.0.0/foo/baz.md | 74 ++++ .../versioned_docs/version-1.0.0/hello.md | 40 ++ .../versioned_docs/version-1.0.1/foo/bar.md | 66 +++ .../versioned_docs/version-1.0.1/foo/baz.md | 74 ++++ .../versioned_docs/version-1.0.1/hello.md | 40 ++ .../version-1.0.0-sidebars.json | 11 + .../version-1.0.1-sidebars.json | 11 + .../transversioned-site/versions.json | 4 + .../versioned-site/pages/hello/world.js | 17 + .../versioned-site/pages/index.js | 17 + .../__fixtures__/versioned-site/sidebars.json | 10 + .../__fixtures__/versioned-site/siteConfig.js | 7 + .../versioned-site/static/css/basic.css | 378 ++++++++++++++++++ .../versioned-site/static/img/sakura.png | Bin 0 -> 79340 bytes .../static/img/slash-introducing.png | Bin 0 -> 15983 bytes .../versioned_docs/version-1.0.0/foo/bar.md | 66 +++ .../versioned_docs/version-1.0.0/foo/baz.md | 74 ++++ .../versioned_docs/version-1.0.0/hello.md | 40 ++ .../versioned_docs/version-1.0.1/foo/bar.md | 66 +++ .../versioned_docs/version-1.0.1/foo/baz.md | 74 ++++ .../versioned_docs/version-1.0.1/hello.md | 40 ++ .../version-1.0.0-sidebars.json | 11 + .../version-1.0.1-sidebars.json | 11 + .../__fixtures__/versioned-site/versions.json | 4 + test/load/pages.test.js | 6 +- test/load/utils.test.js | 2 + test/loadSetup.js | 18 +- 69 files changed, 3387 insertions(+), 24 deletions(-) rename test/__fixtures__/{custom-website => custom-site}/pages/bar/baz.js (100%) rename test/__fixtures__/{custom-website => custom-site}/pages/foo.js (100%) rename test/__fixtures__/{custom-website => custom-site}/pages/foo/index.js (100%) rename test/__fixtures__/{custom-website => custom-site}/pages/index.js (100%) rename test/__fixtures__/{custom-website => custom-site}/siteConfig.js (100%) create mode 100644 test/__fixtures__/simple-site/pages/hello/world.js create mode 100644 test/__fixtures__/simple-site/pages/index.js create mode 100644 test/__fixtures__/simple-site/sidebars.json rename test/__fixtures__/{simple-website => simple-site}/siteConfig.js (100%) create mode 100644 test/__fixtures__/simple-site/static/css/basic.css create mode 100644 test/__fixtures__/simple-site/static/img/sakura.png create mode 100644 test/__fixtures__/simple-site/static/img/slash-introducing.png delete mode 100644 test/__fixtures__/simple-website/pages/bar/baz.js delete mode 100644 test/__fixtures__/simple-website/pages/foo.js delete mode 100644 test/__fixtures__/simple-website/pages/foo/index.js delete mode 100644 test/__fixtures__/simple-website/pages/index.js create mode 100644 test/__fixtures__/translated-site/languages.js create mode 100644 test/__fixtures__/translated-site/pages/hello/world.js create mode 100644 test/__fixtures__/translated-site/pages/index.js create mode 100644 test/__fixtures__/translated-site/siteConfig.js create mode 100644 test/__fixtures__/translated-site/static/css/basic.css create mode 100644 test/__fixtures__/translated-site/static/img/sakura.png create mode 100644 test/__fixtures__/translated-site/static/img/slash-introducing.png create mode 100644 test/__fixtures__/translated-site/translated_docs/ko/docs/foo/bar.md create mode 100644 test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md create mode 100644 test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md create mode 100644 test/__fixtures__/transversioned-site/languages.js create mode 100644 test/__fixtures__/transversioned-site/pages/hello/world.js create mode 100644 test/__fixtures__/transversioned-site/pages/index.js create mode 100644 test/__fixtures__/transversioned-site/sidebars.json create mode 100644 test/__fixtures__/transversioned-site/siteConfig.js create mode 100644 test/__fixtures__/transversioned-site/static/css/basic.css create mode 100644 test/__fixtures__/transversioned-site/static/img/sakura.png create mode 100644 test/__fixtures__/transversioned-site/static/img/slash-introducing.png create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md create mode 100644 test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md create mode 100644 test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json create mode 100644 test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json create mode 100644 test/__fixtures__/transversioned-site/versions.json create mode 100644 test/__fixtures__/versioned-site/pages/hello/world.js create mode 100644 test/__fixtures__/versioned-site/pages/index.js create mode 100644 test/__fixtures__/versioned-site/sidebars.json create mode 100644 test/__fixtures__/versioned-site/siteConfig.js create mode 100644 test/__fixtures__/versioned-site/static/css/basic.css create mode 100644 test/__fixtures__/versioned-site/static/img/sakura.png create mode 100644 test/__fixtures__/versioned-site/static/img/slash-introducing.png create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md create mode 100644 test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md create mode 100644 test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json create mode 100644 test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json create mode 100644 test/__fixtures__/versioned-site/versions.json diff --git a/test/__fixtures__/custom-website/pages/bar/baz.js b/test/__fixtures__/custom-site/pages/bar/baz.js similarity index 100% rename from test/__fixtures__/custom-website/pages/bar/baz.js rename to test/__fixtures__/custom-site/pages/bar/baz.js diff --git a/test/__fixtures__/custom-website/pages/foo.js b/test/__fixtures__/custom-site/pages/foo.js similarity index 100% rename from test/__fixtures__/custom-website/pages/foo.js rename to test/__fixtures__/custom-site/pages/foo.js diff --git a/test/__fixtures__/custom-website/pages/foo/index.js b/test/__fixtures__/custom-site/pages/foo/index.js similarity index 100% rename from test/__fixtures__/custom-website/pages/foo/index.js rename to test/__fixtures__/custom-site/pages/foo/index.js diff --git a/test/__fixtures__/custom-website/pages/index.js b/test/__fixtures__/custom-site/pages/index.js similarity index 100% rename from test/__fixtures__/custom-website/pages/index.js rename to test/__fixtures__/custom-site/pages/index.js diff --git a/test/__fixtures__/custom-website/siteConfig.js b/test/__fixtures__/custom-site/siteConfig.js similarity index 100% rename from test/__fixtures__/custom-website/siteConfig.js rename to test/__fixtures__/custom-site/siteConfig.js diff --git a/test/__fixtures__/docs/foo/baz.md b/test/__fixtures__/docs/foo/baz.md index add729c51d..75e9149616 100644 --- a/test/__fixtures__/docs/foo/baz.md +++ b/test/__fixtures__/docs/foo/baz.md @@ -5,9 +5,6 @@ title: baz ## Images -![Minion](/img/minion.png) -![Stormtroopocat](/img/stormtroopocat.jpg) - Like links, Images also have a footnote style syntax ![Alt text][id] diff --git a/test/__fixtures__/simple-site/pages/hello/world.js b/test/__fixtures__/simple-site/pages/hello/world.js new file mode 100644 index 0000000000..838f36bb1a --- /dev/null +++ b/test/__fixtures__/simple-site/pages/hello/world.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class World extends React.Component { + render() { + return ( + + + World + + +
    Hello World
    +
    + ); + } +} diff --git a/test/__fixtures__/simple-site/pages/index.js b/test/__fixtures__/simple-site/pages/index.js new file mode 100644 index 0000000000..58dd9accb1 --- /dev/null +++ b/test/__fixtures__/simple-site/pages/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class Home extends React.Component { + render() { + return ( + + + Home + + +
    Home ...
    +
    + ); + } +} diff --git a/test/__fixtures__/simple-site/sidebars.json b/test/__fixtures__/simple-site/sidebars.json new file mode 100644 index 0000000000..49667e47b5 --- /dev/null +++ b/test/__fixtures__/simple-site/sidebars.json @@ -0,0 +1,10 @@ +{ + "docs": { + "Getting Started": [ + "installation" + ], + "Guides": [ + "blog" + ] + } +} diff --git a/test/__fixtures__/simple-website/siteConfig.js b/test/__fixtures__/simple-site/siteConfig.js similarity index 100% rename from test/__fixtures__/simple-website/siteConfig.js rename to test/__fixtures__/simple-site/siteConfig.js diff --git a/test/__fixtures__/simple-site/static/css/basic.css b/test/__fixtures__/simple-site/static/css/basic.css new file mode 100644 index 0000000000..e6e089cbfa --- /dev/null +++ b/test/__fixtures__/simple-site/static/css/basic.css @@ -0,0 +1,378 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; + font-weight: 300; +} + +button, +input[type="checkbox"] { + outline: none; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -155px; + width: 100%; + font-size: 100px; + font-weight: 100; + text-align: center; + color: rgba(175, 47, 47, 0.15); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +label[for='toggle-all'] { + display: none; +} + +.toggle-all { + position: absolute; + top: -55px; + left: -12px; + width: 60px; + height: 34px; + text-align: center; + border: none; /* Mobile Safari */ +} + +.toggle-all:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li .toggle:checked:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li label { + white-space: pre-line; + word-break: break-all; + padding: 15px 60px 15px 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.footer { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a.selected, +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, +html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; + position: relative; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle-all, + .todo-list li .toggle { + background: none; + } + + .todo-list li .toggle { + height: 40px; + } + + .toggle-all { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +@media (max-width: 430px) { + .footer { + height: 50px; + } + + .filters { + bottom: 10px; + } +} diff --git a/test/__fixtures__/simple-site/static/img/sakura.png b/test/__fixtures__/simple-site/static/img/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 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 DKbw08 literal 0 HcmV?d00001 diff --git a/test/__fixtures__/simple-site/static/img/slash-introducing.png b/test/__fixtures__/simple-site/static/img/slash-introducing.png new file mode 100644 index 0000000000000000000000000000000000000000..83945788689839aa89925a581f35d7abe4b546f5 GIT binary patch literal 15983 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 b_wbd&t}l-+I5&WU

    Baz
    ; diff --git a/test/__fixtures__/simple-website/pages/foo.js b/test/__fixtures__/simple-website/pages/foo.js deleted file mode 100644 index 3b52ec615c..0000000000 --- a/test/__fixtures__/simple-website/pages/foo.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export default () =>
    Foo
    ; diff --git a/test/__fixtures__/simple-website/pages/foo/index.js b/test/__fixtures__/simple-website/pages/foo/index.js deleted file mode 100644 index 5faf67ae13..0000000000 --- a/test/__fixtures__/simple-website/pages/foo/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export default () =>
    Foo in subfolder
    ; diff --git a/test/__fixtures__/simple-website/pages/index.js b/test/__fixtures__/simple-website/pages/index.js deleted file mode 100644 index 13063810a7..0000000000 --- a/test/__fixtures__/simple-website/pages/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export default () =>
    Index
    ; diff --git a/test/__fixtures__/translated-site/languages.js b/test/__fixtures__/translated-site/languages.js new file mode 100644 index 0000000000..d7e55bf050 --- /dev/null +++ b/test/__fixtures__/translated-site/languages.js @@ -0,0 +1,178 @@ +const languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + { + enabled: false, + name: '日本語', + tag: 'ja', + }, + { + enabled: false, + name: 'العربية', + tag: 'ar', + }, + { + enabled: false, + name: 'Bosanski', + tag: 'bs-BA', + }, + { + enabled: false, + name: 'Català', + tag: 'ca', + }, + { + enabled: false, + name: 'Čeština', + tag: 'cs', + }, + { + enabled: false, + name: 'Dansk', + tag: 'da', + }, + { + enabled: false, + name: 'Deutsch', + tag: 'de', + }, + { + enabled: false, + name: 'Ελληνικά', + tag: 'el', + }, + { + enabled: false, + name: 'Español', + tag: 'es-ES', + }, + { + enabled: false, + name: 'فارسی', + tag: 'fa-IR', + }, + { + enabled: false, + name: 'Suomi', + tag: 'fi', + }, + { + enabled: false, + name: 'Français', + tag: 'fr', + }, + { + enabled: false, + name: 'עִברִית', + tag: 'he', + }, + { + enabled: false, + name: 'Magyar', + tag: 'hu', + }, + { + enabled: false, + name: 'Bahasa Indonesia', + tag: 'id-ID', + }, + { + enabled: false, + name: 'Italiano', + tag: 'it', + }, + { + enabled: false, + name: 'Afrikaans', + tag: 'af', + }, + { + enabled: true, + name: '한국어', + tag: 'ko', + }, + { + enabled: false, + name: 'मराठी', + tag: 'mr-IN', + }, + { + enabled: false, + name: 'Nederlands', + tag: 'nl', + }, + { + enabled: false, + name: 'Norsk', + tag: 'no-NO', + }, + { + enabled: false, + name: 'Polskie', + tag: 'pl', + }, + { + enabled: false, + name: 'Português', + tag: 'pt-PT', + }, + { + enabled: false, + name: 'Português (Brasil)', + tag: 'pt-BR', + }, + { + enabled: false, + name: 'Română', + tag: 'ro', + }, + { + enabled: false, + name: 'Русский', + tag: 'ru', + }, + { + enabled: false, + name: 'Slovenský', + tag: 'sk-SK', + }, + { + enabled: false, + name: 'Српски језик (Ћирилица)', + tag: 'sr', + }, + { + enabled: false, + name: 'Svenska', + tag: 'sv-SE', + }, + { + enabled: false, + name: 'Türkçe', + tag: 'tr', + }, + { + enabled: false, + name: 'Українська', + tag: 'uk', + }, + { + enabled: false, + name: 'Tiếng Việt', + tag: 'vi', + }, + { + enabled: false, + name: '简体中文', + tag: 'zh-CN', + }, + { + enabled: false, + name: '繁體中文', + tag: 'zh-TW', + }, +]; +module.exports = languages; diff --git a/test/__fixtures__/translated-site/pages/hello/world.js b/test/__fixtures__/translated-site/pages/hello/world.js new file mode 100644 index 0000000000..838f36bb1a --- /dev/null +++ b/test/__fixtures__/translated-site/pages/hello/world.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class World extends React.Component { + render() { + return ( + + + World + + +
    Hello World
    +
    + ); + } +} diff --git a/test/__fixtures__/translated-site/pages/index.js b/test/__fixtures__/translated-site/pages/index.js new file mode 100644 index 0000000000..58dd9accb1 --- /dev/null +++ b/test/__fixtures__/translated-site/pages/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class Home extends React.Component { + render() { + return ( + + + Home + + +
    Home ...
    +
    + ); + } +} diff --git a/test/__fixtures__/translated-site/siteConfig.js b/test/__fixtures__/translated-site/siteConfig.js new file mode 100644 index 0000000000..661f59c981 --- /dev/null +++ b/test/__fixtures__/translated-site/siteConfig.js @@ -0,0 +1,8 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/', + defaultLanguage: 'en' +}; diff --git a/test/__fixtures__/translated-site/static/css/basic.css b/test/__fixtures__/translated-site/static/css/basic.css new file mode 100644 index 0000000000..e6e089cbfa --- /dev/null +++ b/test/__fixtures__/translated-site/static/css/basic.css @@ -0,0 +1,378 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; + font-weight: 300; +} + +button, +input[type="checkbox"] { + outline: none; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -155px; + width: 100%; + font-size: 100px; + font-weight: 100; + text-align: center; + color: rgba(175, 47, 47, 0.15); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +label[for='toggle-all'] { + display: none; +} + +.toggle-all { + position: absolute; + top: -55px; + left: -12px; + width: 60px; + height: 34px; + text-align: center; + border: none; /* Mobile Safari */ +} + +.toggle-all:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li .toggle:checked:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li label { + white-space: pre-line; + word-break: break-all; + padding: 15px 60px 15px 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.footer { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a.selected, +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, +html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; + position: relative; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle-all, + .todo-list li .toggle { + background: none; + } + + .todo-list li .toggle { + height: 40px; + } + + .toggle-all { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +@media (max-width: 430px) { + .footer { + height: 50px; + } + + .filters { + bottom: 10px; + } +} diff --git a/test/__fixtures__/translated-site/static/img/sakura.png b/test/__fixtures__/translated-site/static/img/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 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 DKbw08 literal 0 HcmV?d00001 diff --git a/test/__fixtures__/translated-site/static/img/slash-introducing.png b/test/__fixtures__/translated-site/static/img/slash-introducing.png new file mode 100644 index 0000000000000000000000000000000000000000..83945788689839aa89925a581f35d7abe4b546f5 GIT binary patch literal 15983 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 b_wbd&t}l-+I5&WU Remarkable로 실시간 편집을 경험하십시오! + +깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다. + +*** + +# h1 제목 +## h2 제목 +### h3 제목 +#### h4 헤딩 +##### h5 제목 +###### h6 제목 + + +## 수평 규칙 + +___ + +*** + +*** + + +## 활자체 대체 + +입력기 옵션을 사용하면 결과를 볼 수 있습니다. + +(p) (P) + - (r) (t) + +테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! .... + +!!!!!! ???? ,, + +놀라운 - 굉장한 + +"Smartypants, 큰 따옴표" + +'Smartypants, 작은 따옴표' + + +## 강조 + +** 이것은 굵은 글씨입니다 ** + +__ 이것은 굵은 글씨입니다 __ + +* 이탤릭체 텍스트 * + +_ 이탤릭체 텍스트 _ + +~~ 삭제 된 텍스트 ~~ + +위 첨자 : 19 ^ th ^ + +아래 첨자 : H ~ 2 ~ O + +++ 삽입 된 텍스트 ++ + +== 표시된 텍스트 == \ No newline at end of file diff --git a/test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md b/test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md new file mode 100644 index 0000000000..c078572ef4 --- /dev/null +++ b/test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: baz +title: baz +--- + +## 이미지 + +링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다. + +! [Alt text] [id] + +나중에 URL 위치를 정의하는 문서에서 참조로 : + +[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## 링크 + +[링크 텍스트] (http://dev.nodeca.com) + +[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!") + +자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정) + + + +## 각주 + +각주 1 링크 [^ 첫 번째]. + +각주 2 링크 [^ 초]. + +인라인 각주 ^ [인라인 각주의 텍스트] 정의. + +중복 된 각주 참조 [^ 초]. + +[^ first] : 각주 **는 마크 업을 가질 수 있습니다 ** + +    및 여러 단락. + +[^ 초] : 각주 텍스트. + + +## 정의 목록 + +1 학기 + +정의 1 +게으른 연속. + +* 인라인 마크 업과 함께 2 학기 * + +: 정의 2 + +        {일부 코드, 정의 2의 일부} + +    정의의 세 번째 단락 2. + +_ 컴팩트 스타일 : _ + +1 학기 +  ~ 정의 1 + +2 학기 +  ~ 정의 2a +  ~ 정의 2b + + +## 약어 + +이것은 HTML 약어입니다. + +그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다. + +* [HTML] : 하이퍼 텍스트 마크 업 언어 \ No newline at end of file diff --git a/test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md b/test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md new file mode 100644 index 0000000000..9c67f37d2e --- /dev/null +++ b/test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md @@ -0,0 +1,40 @@ +--- +id: hello +title: Hello, World ! +--- + +안녕하세요, 여기 엔 틸리에 :) + +## Blockquotes + +> Blockquotes는 또한 중첩 될 수 있습니다 ... +>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ... +>>> ... 또는 화살표 사이에 공백이 있어야합니다. + + +## 목록 + +정렬되지 않은 + ++`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다. ++ 하위 목록은 2 칸을 들여서 만들어집니다 : +   - 마커 문자 변경으로 새로운 목록 시작 : +     * AC tristique libero volutpat at +     + Preisium nisl aliquet에 대한 + 시설 +     - Nulla volutpat aliquam velit ++ 매우 쉽습니다! + +주문 됨 + +1. Lorem ipsum dolor sit amet +2. 컨소시엄 adipiscing 엘리트 +3. massa에서의 정수 lorem + + +1. 일련 번호를 사용할 수 있습니다 ... +1. ... 또는 모든 숫자를 '1'로 유지하십시오. + +오프셋을 사용하여 번호 매기기 시작 : + +57. foo +1. 막대기 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/languages.js b/test/__fixtures__/transversioned-site/languages.js new file mode 100644 index 0000000000..d7e55bf050 --- /dev/null +++ b/test/__fixtures__/transversioned-site/languages.js @@ -0,0 +1,178 @@ +const languages = [ + { + enabled: true, + name: 'English', + tag: 'en', + }, + { + enabled: false, + name: '日本語', + tag: 'ja', + }, + { + enabled: false, + name: 'العربية', + tag: 'ar', + }, + { + enabled: false, + name: 'Bosanski', + tag: 'bs-BA', + }, + { + enabled: false, + name: 'Català', + tag: 'ca', + }, + { + enabled: false, + name: 'Čeština', + tag: 'cs', + }, + { + enabled: false, + name: 'Dansk', + tag: 'da', + }, + { + enabled: false, + name: 'Deutsch', + tag: 'de', + }, + { + enabled: false, + name: 'Ελληνικά', + tag: 'el', + }, + { + enabled: false, + name: 'Español', + tag: 'es-ES', + }, + { + enabled: false, + name: 'فارسی', + tag: 'fa-IR', + }, + { + enabled: false, + name: 'Suomi', + tag: 'fi', + }, + { + enabled: false, + name: 'Français', + tag: 'fr', + }, + { + enabled: false, + name: 'עִברִית', + tag: 'he', + }, + { + enabled: false, + name: 'Magyar', + tag: 'hu', + }, + { + enabled: false, + name: 'Bahasa Indonesia', + tag: 'id-ID', + }, + { + enabled: false, + name: 'Italiano', + tag: 'it', + }, + { + enabled: false, + name: 'Afrikaans', + tag: 'af', + }, + { + enabled: true, + name: '한국어', + tag: 'ko', + }, + { + enabled: false, + name: 'मराठी', + tag: 'mr-IN', + }, + { + enabled: false, + name: 'Nederlands', + tag: 'nl', + }, + { + enabled: false, + name: 'Norsk', + tag: 'no-NO', + }, + { + enabled: false, + name: 'Polskie', + tag: 'pl', + }, + { + enabled: false, + name: 'Português', + tag: 'pt-PT', + }, + { + enabled: false, + name: 'Português (Brasil)', + tag: 'pt-BR', + }, + { + enabled: false, + name: 'Română', + tag: 'ro', + }, + { + enabled: false, + name: 'Русский', + tag: 'ru', + }, + { + enabled: false, + name: 'Slovenský', + tag: 'sk-SK', + }, + { + enabled: false, + name: 'Српски језик (Ћирилица)', + tag: 'sr', + }, + { + enabled: false, + name: 'Svenska', + tag: 'sv-SE', + }, + { + enabled: false, + name: 'Türkçe', + tag: 'tr', + }, + { + enabled: false, + name: 'Українська', + tag: 'uk', + }, + { + enabled: false, + name: 'Tiếng Việt', + tag: 'vi', + }, + { + enabled: false, + name: '简体中文', + tag: 'zh-CN', + }, + { + enabled: false, + name: '繁體中文', + tag: 'zh-TW', + }, +]; +module.exports = languages; diff --git a/test/__fixtures__/transversioned-site/pages/hello/world.js b/test/__fixtures__/transversioned-site/pages/hello/world.js new file mode 100644 index 0000000000..838f36bb1a --- /dev/null +++ b/test/__fixtures__/transversioned-site/pages/hello/world.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class World extends React.Component { + render() { + return ( + + + World + + +

    Hello World
    + + ); + } +} diff --git a/test/__fixtures__/transversioned-site/pages/index.js b/test/__fixtures__/transversioned-site/pages/index.js new file mode 100644 index 0000000000..58dd9accb1 --- /dev/null +++ b/test/__fixtures__/transversioned-site/pages/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class Home extends React.Component { + render() { + return ( + + + Home + + +
    Home ...
    +
    + ); + } +} diff --git a/test/__fixtures__/transversioned-site/sidebars.json b/test/__fixtures__/transversioned-site/sidebars.json new file mode 100644 index 0000000000..24d61b49c7 --- /dev/null +++ b/test/__fixtures__/transversioned-site/sidebars.json @@ -0,0 +1,11 @@ +{ + "docs": { + "Test": [ + "foo/bar", + "foo/baz" + ], + "Guides": [ + "hello" + ] + } +} diff --git a/test/__fixtures__/transversioned-site/siteConfig.js b/test/__fixtures__/transversioned-site/siteConfig.js new file mode 100644 index 0000000000..661f59c981 --- /dev/null +++ b/test/__fixtures__/transversioned-site/siteConfig.js @@ -0,0 +1,8 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/', + defaultLanguage: 'en' +}; diff --git a/test/__fixtures__/transversioned-site/static/css/basic.css b/test/__fixtures__/transversioned-site/static/css/basic.css new file mode 100644 index 0000000000..e6e089cbfa --- /dev/null +++ b/test/__fixtures__/transversioned-site/static/css/basic.css @@ -0,0 +1,378 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; + font-weight: 300; +} + +button, +input[type="checkbox"] { + outline: none; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -155px; + width: 100%; + font-size: 100px; + font-weight: 100; + text-align: center; + color: rgba(175, 47, 47, 0.15); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +label[for='toggle-all'] { + display: none; +} + +.toggle-all { + position: absolute; + top: -55px; + left: -12px; + width: 60px; + height: 34px; + text-align: center; + border: none; /* Mobile Safari */ +} + +.toggle-all:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li .toggle:checked:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li label { + white-space: pre-line; + word-break: break-all; + padding: 15px 60px 15px 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.footer { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a.selected, +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, +html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; + position: relative; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle-all, + .todo-list li .toggle { + background: none; + } + + .todo-list li .toggle { + height: 40px; + } + + .toggle-all { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +@media (max-width: 430px) { + .footer { + height: 50px; + } + + .filters { + bottom: 10px; + } +} diff --git a/test/__fixtures__/transversioned-site/static/img/sakura.png b/test/__fixtures__/transversioned-site/static/img/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 zcmb4pWl$Vl&@S$7!QC~uLxMZO7Fi^?yOTh0cUjz>#bI&x#T^!cOYj6(NFapVy!Y1q z@%{XsnL2f9x=v3|P0g97yPv@gB0&Gm|e^>vP_&b6?h=B-4gd-yoA|MeWA`>G19Ydi07bhy>f8qXrpdcZmqM;)q zVEnUEAtE3l{|_r75&|;HKl|S;1RUglRsv*#e;(GK1|U$ANFXE3kWljtx=|2UXplB} zi^a#Q!i2R#%Oh#@3WqJpT`C9Ehsi=F*68!ZH60Gq+8H)CJuQDlH^t+kh-FrM`7>!Y z%YW16XDvBUOBawg$3nP)I4#pKHSs65U6}d))$+D6$HY);9cK;L*4PjWjw*CT6I&yW zH3E+sJ|{tsy)~B~F?xd_tX$|~Tt+DR4Psp-OE)QwSarT;Kht`4>9iKxS-M!nwIrox zb48Q(woYsKToV1GYrT^!!)-$RK5a(2Ft)qHcZZY!k;@|rT3(iBV*|x2gDfCwmOhPO zvrn~xeo>fb@SE0vB6&JM!ERxDIQ^Wv5`F45$;>Z~kH;y|V&ZEK1<--L472&?`rmB? z4?cW}aB1R2FM+a0l&KODdD~@Rv=<#hO&#(Wqok`fzC%+$r^Q5!r#CNWtiD#WzCo1d zMgtj}3fy4)xG>E#m{8YCm@+w#l5t`Cx0hR_{)y$LH|CmhwO7+ z6=7p^ZgI2&cB{nI!uA+rl(vMp;Za)`waWbR5UR2#-gT1gZs$!w+SR0yUf! z=LT8E2IN&(5viPIyZLkGQ zw}LU(vDnYdp&JGiFiAEwUOecqV9?`XlD=>^x^RQJ^aV{_y84T}QYQn8i?pi(5l89b zF%wDR86fTY>z{@QLEA_3T0Tu|&f8kc04tUxWmOrri6DH{14*`uW0{D^iXw5n7+hBm z7dzP!j#{3x&+A7_>5$<=68k((yxdJ`R9l{>5c?`zf!uPFQMW(`DuBeN%sC1fRuh3Y!@c(Z0kUO*MMZMV&e{e`v#J<@g;xAkzX zJ^QKBgB0Wsb*hPO1M7vAUaRk41+O8-8aIjPu&i^FBqx3i z3Hwke;HqvKxl`!VVvkQTAl-QdCW&}BFIU&-3i_Z34hW5}k=XYDPb+yO?)W|s7a>AV(6pS(r?_%1YZ%u3*mxxXOz=cFg zf))W{B%79Eqy*V|`D`hQDoERGI7NZP+Q-1$}wJKqr_7$Ac?K_Cl|MiX~*m9jhA(!RpV-ljYGRumAtAa5W zT-*$V$PGG41cokjP0!|Y5F$m|BM`uu1k%~)lZ8piELb;{8e%mX&rPoTc6q48$IVPM z4&tm}ekTPP&D@M7@K`@P6QMq`MM<-%J(}WTFTD4oWLU>%d+mP5q}KUNRr@fQ|xt@(bh7gkV2x!ai#+CvRT!m*29xpK5hy+q`1m;6sg{c z{V)$JtIt%$#wnG=RQJo8gKyo0Wc6Bbug?K9PH{gE#VZS|hi{nQAgOq*LpgoU4C-HZ zHA8@Ab4x)DL{4}vN1&u81;HE;QI;7syfljtJ!nc#Jp0256L+J%44Cu0|8hS z;n2%ttvjx$Z)jkOQA^1^+%B?2y*2KN<@==6gtyN_ih4$qCC5n{TeFZFP!4qvTVWy9mN z>(cQGx8GD4#t)~}BYDU*TNd7_HFwz-cM}jXYn=mGnbgv#?Pk@nF}Q3Bbr}wbL*lno z22#@R1JXfbS@CUeuLd$o9!cMw1T9T@b z{HDHpY0VXF!DG#@7+|j|rFbIR&3tCEWx(Xxb>PjC%h*kyPJ@|D(pr7L<8ktMRyt4C zFOC$ZMksrOyCG)-DQng?2Wu}*<2Qo{CpF+T=}znfE6OD`LAQz|};6pUCyktN`zC=VlJ4tMz4O*?nrCe}2}FKI+C;F+lgIqH|Fn=XO1);$DP)kVWTQYEv-pUr z^260S_mbyf@BXLZRI{_o0=ZNFO~YJ65nif#)iq`t(8pTZh`E`_(s>Q9laAeQnzcXLg@AYR1u?6+%b^`(*sA8{NwTIgN zgbUT2zf+q~1Q=;^Yp+9RgfeuaZXDPMKDrV*k*Wuae}CAS{&`IuUYrha&UekZJD$zti?xsYu+%vc=lX{-!oiI zFHuLddTEo_@)-AkOm|FIN>71dtemRwl`_3n7IV_ns7|fAZGN@6ghI1Ka*%|t)5Sfm zLOJ(|$YUp(SQBH8$9r)5vHu06E9-cWt511bFP@72xoL^x(qNC<6UwKWQJaB5#vMFk zLwV)?IqTpLsnFwF7q@j;fKxVdu`ybw)w{ECqrpO2xQLv>0j=P&u^`;e@l2<~gOVwo zS6wrxof0w{Vc>MK{70a(dgonG_nmH?cpeYsvGaDz8V0+Xkx2<;8!GOEi-jz~fB`^I zdHTGU>oDy^Mk`2k8Ph=FW;{D*S(}VCmgd4mc}BGDIc78!S32^^ON!y?1)tsIrJE zH)G?|)?Fxr;zTSD(csdf6JcwP8=G8fVbqc`eQb>uXt0p|x-ZczuURyc0%p*Kd2dT_ z2`OR5MYs6+CS|JgxlQk=&Kbw`BsUv`+IK+44o6~i)5C1Rkpr=~zt2%8f6fRw|o0h&#>Ms!bhA8B3!@Y2AApR9ZPKk*|OSTF>|L-iMII| zw6#-u&Qq2c68RDlLmHc~jy%>P1G^jNmJS*F#sz;5dLi$6A`^{@9n;i~^=y2zylc6s z#0tMsKXHa>0K1%#2!Ngdqz;CTD{7M(j9C~r0V92s)?xr;V22+Ey@I4>@wOMRfKzz& zg#aTVl4T+q*;ptHMEO_<-Y|AulP=G>P~mx;~*q!Si&iMCzxTePMbW_cvEwz9zpuZuMr%Hu+3iHg~PGB2`gDIhzg3u<^sXdzlbp^bCP5{)u zRe|AuIw=8WoYOH}=hh9cO*%v{HfCOb-a`9}AhXRqV`011W5+u{V^4|?Xv%J@9^}|> z*QtZ}iqs|Lb;=MS4^XF0HnW#GH=8tI2yw0B@?{9Gx3{|GJL5f*3NOegnijHP9F>c- zGFQ)kY7W4ZfcvZuwHY4$Y6~T!yJZHFLHHC^aMt$m)k*XqE^KyE)3^>@85=3 z`51(Yb4m$};Go4GsV-pcqQ`H^_MQxPHootl{~{#!eoy_WJ)|R#AO~^i2wXW)GRt=P z7UU?Bd0p__F(6H)EZORwE8(XHlndjocVysLITf)bvLU4Sam?+jwzgVbQune1SUoUo zJNKm2O;~IUMR5>HLOaYtwBQQ69wFA1_?lXDP5_U z%z(~W+6P6KIX`q?KF2yE*EIFR*=fk#1(i5~$SEZgp?}|RIB9>2!bjh+*v9?1+-Nzj zQz_)suKK&4igTT#WxbU#*7iEGO}WnyjxtNUl7cv4yn5Z)^=Iz}ic%pfirRFr>hykE z*?ll>HtVV??b^HZ8TGyCn)4yKofhwYKn|r!rQ*W;4josY*QZvrHvJ4^kqetgYlbrC zZHnSjfc?zlkCLWQ68Pk}6L-az(tAJKa-sH0$3tmdq1tpSlIg?AV^f)o)Cit(owNP= zZ`(ee$s(j$<9LbTR}yuS78FhrSQV4P_O)k|_#w>wECwYfK3qngz6~$0ZAwbUn(por zNxd1AYihg=5%}dxp!*V(f{qtMN)C30O1s7~XC?35DuwVSO}qZ~-?|ZBB)He8*CtUl z@Y`7|bgHY%4NDCg%q*A(i<=BS-;ElZrTsEwt9U2mzlUkBJJ!oKGSC@leL`8)R(sql z@C&c@M~=wV!<^K5({y!BWY^Z!VehJQ`+d+=0+VZ5TU!=zDG^|7y9Bm|8`iT*wrxC>KrQoJRBF8XK#m*2!t;C*p7x(OFta&+CDS0eSQ0RT&1Y zw(9&NG!d=zWah$d9WllN^9^OI;RgB;BRfD$2|UgiYX$MlCUR+BW(&8q+D4*xL$ln_ zr;)bg>=0IjuPnp4h3G40QDS>z%6=wp9`=3y&*l}+WSf~{`c}o3gtaq*JU$AA+Ndyv z+pMi+COPLOIk34IJrae}Mgf!uzk2f5;)zLB=d3WrByRSsquJE)D3ivy2B@u0*WZy< zkZWXX8V~d>b=qV&Rq|H;b{1)%ty*`0y!7TaPULmX2q?hvB!PP+8X4`-o6)8EH97?t-t%}2_xM<*JYzG%GA>jSh*QhLvw=95Tjd*n5nZ+Wo&0@MD zErX31p-WTdNzLyK7K*FqovIrSw+;%GdS?(X?jZN4#g%m%G?>mCJvM{yD^^_1@xr3T z@}5IZr46H)u8bLsd7TmxG)m=;<+{Qa5~jHhDbVr4`n%3|N#yJfS-nz9Pjy#?AKx10 zsfd|c>hhC(FhV2>pi=a|7Wen+_akS{%Z~3S{H8p`DZeRZR@ZQ76y>w7h)ZR)AB-0u z@@|d`)r*YD&puldm5ZSM+EDHEOqe@9OHsrjL4XL)sZ2KmkDZG@`ITo}5{VOgrlEXnIn?6R_srHIO0%s+mrk`X$LB2ng?09JnpFtjXn zI#!)O8IfGc?Jzq_UxaW@-BPpg=aP8{sb)HJMfKFoc=cj2(@PM^bSM^7vwXu=1-z98 zHP|Qd-%8}p*VUrMY*QfofE>8yO>3URU6eCjMqx(jN~$9j2quybusG7Ob^tpvp}?Wm z)@(E>eYgjC35EQL-&kIgR$P8aGR)!wDv*g|G4`~XKWkYU<6r^@h2KvP)7KNU$del$ z@6h4|)je})D|+ukM!nX&=J*UZQoJq6H4r5IU{;r}&%&mVlp?k!y?n9B#`?aw7MvI@ z!#}M3?jnlo1!|@1_Ff(ZU;t9P*oz*>NR`s~paX7$YzEh8O7Mt1Q@*Vla&k16X+W%; zW2wj1p_&k8tYDwQ=8Ep=$`_R1N!7syk~Ey@AVk*^eh%NJ?@(b$hr0eS#%p3x^mbHs zugsTcC?e&Q8pic$DsuBo%8#-djm}oVnkVfgeEU-P5pO(B2{-c;rH6dE&6Fp5Oj%_d zK;2;?w8EqnCn2O|yX2O;N8oE2(GC*mXyqX_X4p%Va=NV71RM8~n!MU%eZm4tGJd2k zxz;%kgq955LC!!;N@V~B?zF0I;f8*SH&$H~sQ5T8Ry}>^|Cp#kw1_M?5YgCEUnfoG zee*-493c%Ud6lkZBjb!j1j4vJ2x!*$%)!r-$0d`N>~^$RX-&{hfly&2@%A#{@G)Xz z6L3YUDODrcGXL$Ih@49hE`b#bThK&lIIc}=vZcUtY_`bwEm3I`XQADKdIxor8+e)R!AV83gnetW3Sbh$y^gT}Ow z7X>ad1MZ-(El{}$k+Pev)~_v284Im`jkZ5?&0U>}m?3#GU5nflQ=L!&D{hn@n^za- zrZgtBTl-v9-s-B{;|<4wPt`rH^%VgFDkE>q?)0zfFOJ7|5(8Kix01K6XR|JR&1ehJ z0Te@6jS>wg|gU$IB3J7rb=Rwl&gvm zU6`W_rVlDFCAs=p2V5*5i)_c^0WLMs7VHx&>{Co`#1otQ29WPB*hh@+GUuIBE#ke` z%g-H!8i;M+^mK11&>h@*q`*AckN{y_;J)1c;7cw{Rk!xl(a5QtpEQRCsAQASiIczK z(PZk;C&}4;PQ0-bu<;GfJgulvOJUVTQpw!O0xVvx+&@R~?W(7*+z(nCb3fS?I)2)~ z*SHX|@Vs2+0P}3N&tXx0gX50F1-hRBvoz(Is+8P|ls5a}{q)8P<0g%(SJ^`6RO0Dd7fw5G{T!XO ziI#~rv=mjL#7v=e3UVvd-{_p$=HRbLM@@y)U7@BOv?*di^+U}MRtmjKg9@5i{=&ao zC#XMmI8@cD+itwE)-IdQb8eYk*GuM8{5&XrYZfZZ-LS{?AZGGYv|4i`-`IJLea2?X z1!#~pZs2F1QHxw$K3P=;N3?TO#F}kt==j?28ggawI$%1cE#^9I_H0b_;3^`tR^+wg z&KxPNcSPloZp9kUi+6?3xAtK2MTznIeU-GJ9*c^5>FI9FXv4;5lkc%K?CZO?k&cIQ zK2n(zGy-tvmO~GxE}PC}bYIMYh#^x%bXy?B_0tw8Sdy2g`?1dV!_r%Xd+iQT`qc^> zpsCn}Cbx`xLU8d%AWF{&?}qzm6ENCfBh*JAkC#WuiiiF83rqbE40y`;UqN@TN#kAg8!mKsZvvXcNfKfY^!)haO5WwbnD0c=W8!(vhYMR*9MYH^=*GuV9X+g zuq0PZXN3Ps_*tj7Hmj_tF;gW2M?`&xC$@Pl5cwQWJCfolw@X7=eD9EZE%B zvX_vJDP93jJnq3n9d&`TL7Dolo0sWNRdsprcFsNhx{2JNxx(-UceABG-wR z6?zFIW8H@JgaoK08);d#0m08>zQ)?l1Tq-+<40mPpukbkdBJWv$-eyUBWBvCz*Xkm z>9C|RTevH1*0-76p*T*h$(lgxydJGek#`AvVy?{8%*mwoWU_Nmrh=aJLKDZ*TjYpz*z6~k6H*UD`!tX|S5DO}s?j5DFlxJ& z2CtdVm(*5Wb}%%2a4vN)i&~UIk5siCQ{k?RG}Fxt(n6YQVIKJk^H=LR)mE*vs>+S% zGj&w|yePp1?J*C6B{W!QN(h_Susq=w^dJ0;)2gcssB`06KNje%0VI5a@o)w)X7 z_D+K%H_3=QY7-?HYDw*v(UN)AUjy|o=AQ$ujDsEr{ASd=poB_6T3qzP0{tOx1l3p8 zchm<@`NzdjngU0AXrF!KuUuWK`x+a5TWF_oSv@f435BLqTooGsYezAwwK+lYLRDL{ zTAvk0gdpkGiyQv72~EwfuGiR(4|ZuQqo>KXorSPkQLW%+Yta*!(>Aud)~&f(qgGx6 zG)IO@+hTsx!!2tPR^cQ5^UBqBUX$>{FFMkF;b~vxs@(>W;DRMlo2R>8L83hAH=AZY zQ%gQ(AFN5J-fgE}S2J8_D{-)a{InvVr06zx6J)DsY66889gXAqv5CyhsQk{p?v=?B zMMqEj!j|$!S>|Dsf_lnwKkc}Ic)hG+_AJ#QTAc9TqYTanWUVUaE* zUJxwKRskZ9?T-5Z@dbs|4C(qHo)~c+R&E+ZO3`tUHD+ zm5qqm@;hl{aWnl0emfKm10UDncpFTwb3()Fq{Yo0Qv? zmWPMWfav+Iej$~{TFzl)j(0i{HS6Q@^u3|9tKS@j3Xl%K2)3xH*UI=8MTKg72AHb$ z1)J;RxpjT=R{X%gxG%P_F%511;xz8V$PwH#pwrusGxb+TOrMFwkAP0Yvw`yE6Ni30 z;ruLHw&DwzSw|9i<#rl}J*Og9x-k^lBLY{hh0-uq-Ts*z3!-m7F=voY)iVP|P2G~R z5kA%A(=sHNz{Io^?tOSeQbS98F3m{pMH+T-<;Z=8Z0OF+aN)PL;?%_kZdUtOYm7KM z####>KPy=^J+;gUElS2FZG{w^FMsMkb?sWgI)y)S?}%+nP@=w?n0P}4G_Adu72b83 z;Y{&6teaQ8QGpl#6CJ!IKtM!6`lok5K}7j~;sYcE#DAg#!hdQA1~f)~5_%?q_oU2k z1<{4%-mwV(QzBse(=Q;RBDue!{r2lfnEscREX`Fvmyo?y8|oY%yiX_7fkkU2{zZ7< z&Bfomi6dhE^6ASDS3*a1F##^Z>Qu9Do#do{5p*N90^^ciTb19t0SxX%t%9D8QZG&p zb+l(qlz_lX$bUF+bua&u^eEw@lJ@x$9Gvtj4Zo|m2ycZ3^>+9PK4D|rG2gtI%DtO3 z6$p%IW;MAyP6eEAY2A z#ZOZ8)**wY#F@O~?nd?W)9yy+{|5EE1Dzsp(f+l1e9uVu?m& z%5S2);rW%-Cp(0lfgwR~i*e@}cLZYHmy=SBTGj1SdxM!l_og;uMW{>@n$2pO>k3-` zhYgmF-yI!=D}$Qwt*xy+z+VKq+WRAYjl$J+5}oc^;B3ml4pm_GwC5s#jp+JSB}bE3 zl30+^on3lXX2b8^+z-r^EwucrHgFu}w+7H$&mDX%E^&I9-+0vM)|=d$(AAsJ(+lqD zZm9BYziVS_=4imege?}W$UKYw5^3x97}rae2dSnw=BMGO*=>7zD^O}lg+&aHy&%vO zOs3v0kq4sr*}Si!^WgE%OI#>pwC%537g^lgN}0AZ)eHC3+B>y{uqvu%+R20L1H3dY zsCso^_Hr)gh3?;rK890I=xS7sJR*v$gc#e=q~JS@Psr@CA0^!S!J}o~Z!h`v34J1@ zl^-w6@yTsp3gNJcgDKvRcd$S|QH1ST%WP#;`BJr2*<8iyVC`QfH1c-!9A0X*|97gJ z`7eLo7F5q{VT!s$dhpibtTI&vOtsbUvR7Mas1AHLvZFw#O_)8|j*m1oGM>uqPnJPr z^;tSs#V1M@v0`6Q7^n7pB7cNTXvqLa#JXdz4*d2%B6mfNeM7TH@|}xP%!cbFUD#oea<>uH2FAU&jKg#lg{5|paKQ4^1y!t|Cot7+ zZBxdW$0x-GdD<-%6g7wb*)7(D+|@+WUPY2Sg>6t*Bi{FI8>HDtvDuHaB^j|Tt~Y-X znm|R2#5%oqlkVEP380`r6ANHG5&`r*YBjnXJ7|_Bi;Pk<5Q|EScB9p4RzOtc3$GZed^pQEYEm z<(klYoA~ZM;|2q#Z$5Do<8F&l5<$l-KXVr`pjj#uwW?`iZ%Y`q#yan?hH9){vy7 zB}QL1C5^5!64%GpN?AKo#YTDk$C1ld`GKorXHe9R{K5OzxcqUQA0c=(*Lrj|JeBlf z(6@dpN&R0PwZ?5$`y9j5zZuh1H`=KoytI?hZL_pp5<=qU)0_BN=xo>AD` z43Usk*2o2AkAy@PADV~mq6(zZedYUxY`?9hjr1yQ=6uoiQuyZbWdfXikUymF{;x&w z$bT?zGJ1`++$LolwiL2cef>*sii-&m$=rEU9doGjiu2bLr`$J&lIWB>#mX& zc|u~_Uj*1_C&y(#Vl_gbmq9t;j^5$=tj2_xqVPbZnYgYRE_e)XKlPkXz?N##LuPD> zvedOKUz^oWZ4;@$AD0dD2(HbK`wk23;Wthgst!rMbTAWaG*cyFQ(pX{6Sv_Cqm+g8 z7-V#ckWDf`H?OU1eP4RvNqVkhK)F{Jy3_G3a>ECr1EFuV)K%||b~Hc0l*aJh9I@uv zkz9M7tvC7RmRQLfq>hqvxFeu8>8#v*0mcIgyE*zg9&`F;XAg*5>)k1q^ZSu|n3lz1 z8JlKsV%A*mEql|99-p%w{L%I0bk@~_iZ1~@L)u5H0COp3@Y6Z6ON}T){^M5bm%MJt ze$&r)I7TM3JOBnqdJ^BEyw4xgxz!>_X)jlk`O{H`D|X2YnP@&tb;w=u0s5NptHUQG zWL|9bO?0ojSp9Vd>Cu0R#sy0|#C`sezsa8l5ondOM zj!|1xfysWILFVgSBmVNFbQ$cF!ZfBhtI7^s?8k z+_wKPGR@hipIXbX?0JjBlMa0b<1;Pbs^YY)?KWWYBe~N`9b~ZSS$+Ddc--Gc=Kirn@mRp8lnIqD%RJpb%1eu`eB~MPQd-#RSd&%Sas#PoE<|^nao>hMB?|3d zC~bS{zWZu5vDS!cLP{es)cfJg%9e#St$xiDP#Q3+z9V~OZdJ>bm;rlSkWBv=NJ|-4 zcTR%!&QFtH$-wnmnM)#BagMlJ{;tZ_Hglx@Jyesp)pKJfCfI16cIUZu{I@pUVTWV5u6nkWxk|Y&!bCH5s*{8? z@>n&nS%9Jk5?D?HW^}A-GLov^cBDHmS zIaPnCA-s7jsQR><9ossiSnlp8GuwT;R^j@Ncu$ePtshj-C^fOP(W}?mR$saOfE8>M z0*LBc#?6w&C=&Uc)YbbKGa(Y9qvW6}SjEg6wnF5kaJCv#%WXt}`R9FVn_bjXHG;pz zBKBZH<89l-j0q5^^+zDYLH930@Lz=A!V8%K0U);Pnb`bp;|w2G-PVpq&gHJ*gP0+=ufMvU3N5yVK^0B&>b}4% ztDv?~P9zQ0LQHxVsF&9HS{J5iQ;<$mC?esQLTUB3j{Y`|2Da)8o7NvM_d1d<+i8Ch zY>AIiZ<3Yo!&+{vHJsBK^@zIEZhwKA{Z)-KXB;bM-OUUxc^6OUH~3-aKK5r}4 zXcV6QW%@gUA0FOVs!Hezk-dg`x|L~$#MTOj8vDv|SNSY4{|TDnAHX}#r-8%gC3!(g z`^$?sF)Oer<^AtO=}Lw{MmI8gws;d=f39CPHx;{|AcLgcPsr*Sh^MKslFXKVaJG82T4(z>8vA2}(esh-uY;aPw0 zI8)5X|HK?{&*kL8J#X+7;C;&gCIYY2(z)vl@-iFP{kYni(Q_>8);MfNzCn}A?I@3M z;NqRgXu|?&a;;0*FrQWi^ZzzcP)mZgJbD@jb(a(g$T~hkUo0U}-}(e+G|s-lRch`6=NkoIo^6 zS6NS~ct?X;_&T$fui_vt&%0+gr(lBJvW1VzUwMuZcjS@cNtQUMG{w)23r#c9J3d#m zo4ZJ`yx@ojd{a(@$6#?PYjTE36mhWafo4%Q00$q}*JF ziel3kwBA{>RnNx%W@R_uqukJXiTZmt>ZtX=8i(o@eH+i+i zRnyD_3~}m>(*m|@fA`s||AJHXB(nJczn*CFW4!LOi(CoL)23aSI0I)?m)Mn$vU^%# z*1hFjJ}gY*GqO0=3(%knfMJW0!w71TXTxfLy-G8p3TaiKXyn3MmU{~&W_6Ak0}KKS zjzj4>X@c1;?LN9S7N#jfxH$s=y1d-l-88b3uTHGHSMIjY@GT<0&(agnrRZQOF9y~x zExDd%o$?mxShF0VKyaDDB}Zxk9k81v*Zzr6r}T@1Ea(gVNunPT&IwEr>#g2c1uidV zHbXwq=kn?CX(_Yd&3GCVewQ%FhWpY=Ey*yXn08I}k7R(!qrPeIdW>R|U7zpp@pM!Y zYRy5;5xecy8;x8665i0*o!$3mH78`~X{;Ujs_mQj)H}(+YP6DDgw}VLA4lnrb z4u`s96){dGb^Yk6hhu`=9#Yyqfr`lqkzvon`~Huv;%q`EoebtpZ=0em@86yYL4MVx zfL!}efBtxplFrkbQ3(l_Obfv$nC51~iXJ6G-m=oTOeZ#5+c8_cE6ep4sct8TwrBNU z!B(LEsvuRAecv>)$N#1s+m+&X82sVSkJNIMAJ@UGYZ9MTtn4t5_dd#!dajl~k8;{? z3;xnNtI%dVY3EXZm0Prm>f8Q{;MbQLA~95+WTWhz5rX8ZaC8E5bhOqem-0>C?-FcJ zWoXu6zrtil`&TIOG8^CZ-Sszx0jDQTUAFSJXQ~KbncpYG5WCKEC0^+so1Vw=hXtP| z%WdS3t^a*kG>on|vh9BnD&(IO`{cCBd}OiY6jbva-Ym`?O#E@1TR9Bu#*}UkpPVi!>WTr9X1uWWNrtYF!7*c-XFN08W)trEA zUEAj`RxZSf)l@%4vy`583-(UUn*LNPw}_v^CVq= z%orAam_nt`1*?e$bmJx7mDLk6!+|gwfS#fGtW^G^^2?14V7S+gR!ZXIBgF5@`sh}B zq?C2&bIU{`@mLY*@Uw)^X!}T02Bx4V74Llg{0RM-P4G{e6{@z(Z95ioh2>8<+eLq} z;crE<_zKXaYUFO*Ul_}@t&y0>UWi8@h4AHCxFh}^ z%bhTm<-3+Xdg*JIyFk<(Izm_tTIbKXYcq)x%e26Y%Lw-{>#vR?Q7tz$(rY47NO=+O`;OO7b~!E$ahwSIR+?>2Pl1S{g~7sv*o=tb)6xa6EQYG;uWVd`;R2u zBkdOPJzoFzJ^rcu8rMgneH4QJ=);w~E3%^UdO*XdT=VB#MwqJG$#S1K}a@)7)(-OLrwoQFX-JNTskb4rl`sf}s0@+`D&@CobUE623 zvVV>QJ@44c3#UxW*$#xW1FJS}FTv6&+KNY%! zpOp$scLQh@Y5&#cwnNW^kA}w4ph~Y7RL|yHo`-{>J}gI0q8e)MyIgF9x}DVC)_*j; z2rIoHi=>c&%5bK@w@S7vkY;F4h}eylG^@KrlHeb=+!RR?RVY zh`C%^K}PR+;SwljRp4i^yl=ivXg{`&ke8qn`?eF0PzDv|*DrLO5VZZ{ks>YuT(ftZ zM%G;hW%djxOh?HXGS4z=bsj+HOm4k1g&CLFD5~DF1SgeE6Z#t)uhp)jcV-o(vaT&n z)VFpXATad-9Xl*nHj|RzkwWd+spo_uHD;~%%>xw?w>?JLjhElMTz*E8T|Hbq25nLg z>c#{0>~G_9aZ|nPliQeOY>(F(uTa%*Q|5c@2wy6V?lh2Lu|jv*Na=3ww*5JY?!I5N zCGFYldKFQ-cL&5E<~iY`X2cA3HZxCO@D^57*S^x{U1{k~SV|XHaaac&zaf7d$juE3 z0dLKomf3+_#I(_)lKPH>yeC|XD)D_L6TGxS#JkGUpgM^syu=&qv2fDwTBVbZFj$lT z%4NEjkyOHm-U|yYKMU0K&k3{wg#J3sk@}PUg>7gq zP-Gtq>p(J-fmkuV+e_+8+2sV$vmF9e1gXyRtU^5JQf6ku9Cn;*;l_eeNQE2^sMl%L zT8)}V?Y1y*y4eUh?0`6j5?|}6s7O-mdV4B{l!B~9>~q6yd7{{YVB7ofHWv#*yF5_o z_ZEKY<^pU)?7p_uPacI_s|z$vj%I%m^zL$%3W?$TzUO}tbfkXRa($7XQIzr$QOh)* zb&~=9f<*T2)Gbs)Gy32DMR+2PjkK4PVb#-S^wt%Z2*p?z6ACFB{%O)cexxy=pQ=p1 zJDQC#-)v5mF(TY%fW*L`O5rHUb1n%^KITJM&t{+wM2c3=8P^S3=1zh#;@Fbck5hN3 znuPy}<9oJ)&&9!a$g7>}r<1lOl?t^Uz-fa)kkQq}4+V_lP|O0iBa=b+^mojmL|||# z3`2m;W?D$4C#aJIZabm1+O#{SnOb|k?Z>5R;?=|we@$yr{E5N|(?sRw%SM9tLE{Wm zY8)m`v9p6BKuO7{NXBcNkA6O64K`)a=<02XoNsS4FRBJ9YxBf$7bzvxcA2d8lU0>gxoi0=;5cC|d5~8R+$(RnJMOfeuSd=h@}7+Hb6gNJAH-R)ck@ z4FqGTuf#nt&kP7aPW@kfFSY*+$SC2sz5nfUnv;5MXjA}H72%_p1&<8Hnr4U#;v}jA z&mnh>x>UFq+@?y_G31_EF1r;%e-r_F?s3d^hCC!5M$dlE$SiSXeM>DTmt%u9$KDyk z=Yhh&H*%St+w5AeK?O-@fF?{H1)qa9yjIVhOwZ18gceC%Q#6**^m=zLAOxOv0KN%H zAEj={DHZW13m{CIX!mIu1PZkRZi6b)hU124Ad%H-S=ip4{=yfYb&JCcy3M3RNC4ZAB_Z78 zPo!r?*>AiiB&g$Mo=Vyeuf6JVWpq70+bDZ9&&|8#Y4OxgAUJMD^_R8BzCrcsB?u}5 z8)YmLKT6AI#zpgKJ|04i5=-=je2;z@9%bF8Z{-<&;n*8ZlYF*V(%Zz!so@Njo6QMX zcH>=ml%OYeUd2HYwM!X`$ji*G-cj~^HahmBY@aX|ShUHh0$sZR zfP=obq)In3k;DcM!e7~3Ea<>#8Q8My?T192Un-CRrx}qIl{I4+fy$w z@cr1~v4y-&PQQ4pQD1NnzksEQiFuH7)zasLKT%6-UF(KuqDH@4viL){`%&Zzr(?Xf zf9^ZTRLupwPvm04F@6qn=fXqhWMY+z@o-cj&B_B8cn@D-ltWTR3j<3gApu&m{ORJ{ zxB&UfwJ?W%#a>I9J*2%}FoeBsER&j0vCzf+MIbk3V>xy` zVs$(##d9Y=$GZLLT>hky`#NHCVZp=hH+_6fz8oN_H%B4q=W_g7P=&=mt|gy%_tsL0 zY|hmEeA(^`KA7Y9{eCS|WOy*dh@u`=F^$j8y`czKs*7>1hEnoRfltFLL9rGqkHFZfx3jphwSKPVy(;f zkAuo`7M22jx&r*i>*W+koc83>ma+W4au^?TDnS~4&^y=dvCOof(1YjZ2Ul^V4(ZWV zVL^&FlLNHJfz%#b?oFVd7~j{w<@gr~lbqhJh-(hyp&NCnu`dQE-Mje7j;p|_0lFJb z_38Z%Ey9(Z=@4S8w=#v5ecrv2w%V}1FVUku^mN!S(Gm~&>nza&^h`S{kp!Kyc^k0N~qCMa!e|($EIJxy&Y_Xd5@hC5BD_m#L z?k~c!X}a1Yr%6#cs%e%1kijB1*fpO}flx`ak|MbHxpfLXO+mty`yqKvTOWo6k;Y9q z(q=vKe~UjpcxNF_cz1QV0(qbckjoX_YfRq3#I8D9SblGKv`uh+B{heq&h7O9{Lp!( zoD!}wG{H8tNuH1VfF9J{BR)4J~TtP74aB=qW7F$`srxq3R#rM0)-C z{9z^m&$2?ZgAR{xH7nad-j2JywVPMK%$clVg<$fiUs`_(+Mjel*|+^+cuxW{(T<_V z`WFEi&isesxvg4HVPa+I>S}(52VY{-*}mQ&3DC_((dI2&UI`G(Iez{>JiT`~+u#5H zuPtruy@`s%s2!t}(2~T8z13)mttD1%uiCLfs8yw+c2O~lQZ-|glv-80N*gU|uYU9X zT)*p=D}Uw6b&_+Q&*wRh$K!TC_j5<0jEJpic>gOZJ9AU2-^^pXl>utP|6DG>KtRW# zyl6l;;a*QKI4N*MZ;sz{E$|zy?QuC^U<(y;qrwAPv*^!NbB(I_xkw0Pc3%1orwqe4 z8i?=v;?iR$@fWYU4MjJR0Kv4P{7ZrM~S=S-rV ze%6>5Dd)K2kI{jdjn|^Z+5gvRG3`CwEXqDKk_1c_Y0Crgn&?*!DTGz`2#PaKYlW&p zJ<4(W_xun>k1YyC%TI@96;h;K&alWMq}L>uR$@)9=$7nH4R=5{MU0?C@k+RQg`z~D z2ok8NXlN)d30JOOW2I(c6P9Pc1-wrKG35}EQ_y;ZzRvk9vj`n+Vpk;Cp>eh$O*AUVN{5`# z;!AY+>CNyG9Yrr8Ag72{DKrve$MmhD4l{>;b0Genlho5>ex;ZBV-cWrI=K2%pX zPMZQ6>Tew2qHO+A0e>kKKYzZv#+2~)hflr;kgLf$1XqlzhShkWRq`m!0kshfJaW=+ zA9}31pn&4Z>l3zCA|IqpO6!7Ujke*_%EY!M^PcmyIL5s*9x7}623cSQQjfgVO?I}F&ksRoORmQ4yu6kdO;mp2D` zB*3~=8Ut0B{Quu70*IF7@vX0bmv~G0=|R@orRF@z1n{sUEwXT2D*2;&-iUx7dea2# zq?N$)i$jj64YIn+#@CaIcc9aBW&20v4JPGS`c8r!O*Jv10jkMb|EQRt^-ox_I4f)R znc979YA2T`rP>(?@%u16dw7A0i`4Qzb)?lu*t6ctSes@NVo%^QQWbV|*1B3R{yZ`> zU5EX~RrwFAGWjZ*(OQ?t{GPQQhuXRk=W;`|n@wI`xxbD=fvN~jRUk9lAL1(LLy9#$ z$vKCNMK(sks~aKoCF}UI)`ivynO)BPEliJ7e#JoWvL3J>xg9JwG6f>WUC=3 zql`?pC|efZGqDy(l~TW&JnVTolzl=0&6lMHw)WEq+EG-5@$)QrTmJzb+DY^SR!|VQnoFdK_G1Cq7rs9gzYP) z&m(HqW_b@g_$%}PIOGq{_|U)dkE%z)Ka^D&*p)FnxL&)$-Hq`r%*>>vU&p*D!NGmE zQW47G26)J)(bTu2`}YrGri=rVO0VA#%xg)$l{`I`)C1D=Qk*{Zmng2W4ZN{FWgKUx z?S?o^{0RXlC&tX+qIA24JCcf74?{lb))ncOo#%fjy30;fR%3#_)^f-QeW3R+MKXs` z>lf(o0Zf~pf9@uRt#mW17YKAY(jgvq1hB2^Lkoy*AsUHj&BD0-b5Fg~^?B8d> zZ^aS}T`@&XZt?f6iSO zd{zw@*%L#Rj1}gMQPyiAk6l3G#O(WnM4@X~M5s(>n#=1T(ET-{1fwX-tcM>5n(Cwt z7WSFu$>%1rV~2Dx&tPjLkRo~!WXjgKS)7IG%an~|U(rAmcnzTnL-u@{f6TFU^GCAm zDeChIuud79a@xh6l%^P$Xm8<69oSJX=7K?8<94sZCjL=*J|{pFz>ooh5)2Oq%~d%S z_BZ>Vcm$XzZG)IgP6V|R=z*GH?rT2Zo!A{@6j6_R`n;ggW9Z3y)J?jrOATDI&%_!=<9jjdkdYyo{3NxA4foRM54Xwpq z-As|>|K-DVk3gM!tjX;@a%25_nyRd;N8$t7tJ`UT;_Ep;gmmd-mMy4gEFBgOe28@; zL<5qe(44YEH3xQ3mAcHU=ra&}Jrel|WI2n^%Vir0Ngo&@7N(}SGo%GSjJc)BFWg6< zdCPZnsq~M^@4U0Sm0HtPw+APM^@ru9i1Fa<%DZ$g2{ygAr#3X@>j}|Bp7mv&+LB4B zR96z+8s|jPia;We>pL43=H%L?cUi^`#JNuP@~?~Y41CgRq!tp^0adF!OlFn6{uDvC+hQ0xc3gHDbt21xCiBs+;oYY(()aQX)_`yx)YT8La@4#DW0ru zcljVFVx|I(KbqXpoUPM_Ifv~GFM))agXU21Nk#wlFjc7v2J{Dv=sBn7>e?RgVJaf= zs-KvV-WKtG?LR7hBNVv7|;T;^*2M>~7ocorvmypUM2NGuc$s>^)qCqSOEedBXMssQOWMrlhM4`pcc)5LalLho-o#%a5J-`12U7|W9b9l{%k0P@YjHlh#$YgKvc4$F} zKQ6lG9~GuKs--k$=V4Ofvd4!^DG}>1F%2I?jQ)-4{OZu=l%aoAldxhGDpWo}I+F`U z6eFV>!(8wbtMRa`nO>c>H-jH(Bo=l~3`W=CNdb@(6ex zp^ON2yIFVSOU(^rC2ol=C$F7x&h_>Lp5W%>pPV5lFE`5mQ3Zg_jsowJ}UgI1G-3w#$y+zPQ-HueJ%>rRCNGb zU1|31idN3O1{wrgclQm~;RKsF1(D1lq+6}OqMf^%8r$+))R#dP)d-s<=dFD6dYX(; zIrzTb^Q0YU=1YQfKDdSMl^^Pns2^@mN>gJ?L;O{Di=`Cr$>Wm7)VPpu1mx5RA@Q%` zgfwE>1(~3?Y z(s`efrq)j-KmQ;)tt|oHv+3;97GMY3j@V4lcMqLTQMJzMn9ht4x2VHvdske=uqt3q zAf3NJrzOIBiG$p9GDN5F7?Ykfl9K{0h9oZ zr|)48*4ag!FHG>WV!_SV@7OPM(zhe&|K9bek0H8W-pY-`M7fv^MQK|)Z?Rui)&FMq z&UGAF>Wk*#CHu0mZ+@DW*h~0}T6c2OQ!j{~t=iYO6>`YE?;yZ6v8K+LmePoW{RThL z9j*Jw2r)-ghoXwcz259E>KD9s6XTSnUWskdlHS)>e;Tz!zXgnr5CVzDzK1@hxiy8+>2mYff_aYMv8qQ?5b4RYZplq|m)@plI1yVpx zzBXW~?TU-!B9{($2F1sShukBnBj2FTIrq$q*3s5of^F^(ZJS2&L9zofTUACk&B&4E zTi{cX(+bq3)=~Gdc<+`vBu(1*LQgqb4`1JBeEB^1RWfQM3DLzS? z{V0YaUle`mGWq4hb10Llcp~a~z$Ck_ZAnWv-yh~w1-*BW2hUYQo(UO%if9jsp&&Rp zd6AblFhC{~`fJa#f^-81<<<=llOGp}>Qj6OALM!@?v0~lB#EcG$x9Cy>S!7asySVT@_MkDoOVo+S!>^h2=rLn;IhV9~g ziu<+$g#DLj!19M9Hzb2I%=!I0u#9A5PPphHY9ce1T9>|&dIjg#6MOxo%6t60)J1}U zMn73M6+Ur(W^yq#vXz<39ixI1&}lqGbHKNK0ebTrhrXdYCBhco&xx=P_%=TAlD80@=kCM(9DSJr};aA#~g9jpj zNtwp6)ET3wftv(mYD%1~H5;05u%SWzW?}mr_FQ+eldHZ-tS|oEUf`hZ2ejP74;gs0 z`?EtkpaTnnLCA)eh9rnjZvW+GT*?o0yve@JE0gTn&;uqrv(Fnpy`*`MjO@$R+N|p_ z5aSg7jMd%8B25Hfm=fSBG!*=mi^$;WT@oq>`>#ViNBT7^HwFqZuB{7^LB%~>Rmod? zpcH%U5W3b9E{RfSci84-eQU+~)@-~Ll(A})!Ur>H4YvX>lCUVC_NUK$JrI%IR#MC_ zf{`tNB$t@>m#_!jdDsK)ys_-)uRZixW=+UuGC3|x^sPks4oIn4TV&mlu9MA4o(q0ii(US<`1wQN`x5j7IhSOQZ1gq;Jdqj*4+P`dP?kZl=1j67)>l|5263x&tr^VV&g&D0{+P9VY1{1F2IHwwW0= zO`Zase6Fb__gA}F>9pE{S%0U;@8lIS&r$ixyu>v6B8g~tZcE1xu6VA=C2{oZYa&VV5>dB^oUG5A=CzOC zvw_|LjDHTrJohb21qb>;+j zuz#42VBDt32YUXs;f#2d->Zxk`wTkehVKCp@$Nn*mirhd2f;O|4vQr$C}`%RG@rLb z!>Y$imTY^!_~T8jkT)ILK57(%G;#X(w?j(z^#qF4zc?=|<8?1d+dgaen!=ew zM5senM7dc5#QRN#Pno)FQ8AJGGw!&U^a(vIhOD|ENr~Wm@dlU*d*K{w|JW0{*||9% ze-#{H7TDrebO6S1>3l8*x#IxTdXKfn8l3hFqeJn{^SLB&%2%meWB_GV88&wn;_y09 z*+25U6@mb6FPz-;3j(Sku(!7gumoUH}U(ciJ*3B&= z464%_dJ*+IyDd<4*7GMd@aT~yJ@JG|<$ zC^GpUm7QQjT98G{S+C5w&sxQSus}K!^8nA^qs}5mM*7M1D2>YLE=OaL+6%s1*`vJi z0R!Clxg9Q-wtW_<86p}?ppUt(A*HWwGP zp0ywDN?3jU{ZL{#esjHOY(2cTGFtc_71)10Vb={A0Z~fF1WgPtjqw$2l&fi|2qp@L zDsFyRtllvq>K%qaM#)8UJ?whbVWE$>ESgDUZsi!QW}Z$6(Exh{bhTA}Wgx$IXWv?2 zoZ&p`W%)a11qm?jWX<9EdJH=N_b zU>O4zeQ@Jtu@mt7&-;q13^Bm4pG^-cgEdCa*uJV&qz@}8d;a)&uhgy?cM>X7%`BRz zGh!}PoL3$AZE!Q&HMKa=BrB_NoOHbT$^UY*mur+TS%=ac zbF7hu?kdO8I%yN?R(Q&3Z_QIsuu&Fks=76gj4O>$F&@u;%3yGEJNwC2is_by*nw(@ z6hSXSS9xU^(QZE-9F8z#X;drSgnwDDUn4n@9XrIGqeXaK4^)iBlU4VXl~r59h9wDx zLj&VJPi6>GDc(JdPkUoEIc3cAPpY4{Ckx(_j-<9%0PCRTo#!X#~N3smzP=POWN{vaAqM>QJHnLfF6)tFoe-tzU@tN- z$x3^YqG>$MIbgLy z<8M1)sK#4*88esT-Vg%pg4ch4M!Sx6fknxR5>y&Aqav$*uPUWYe(0Dt{myDlI})pS z8fpoUcb)fa#z2Oln$M1F+H5!Hmd_Kgr^PSbaK~`;p3xi}m7ZgV%}#sr;xnGDe)zU& z2c70Sjk}SW6|&zlnhl=Ij!3@O*5)`bolInC@w%{kJiOx_WS7)iU<>Fv+gwQv^w^%V zpU+2%$i|)V?Jw~hD-g8h9##@5B}U~3I)|$6jhk?n2j01#)arNYQMnD!!ghAk0=Jg~ z-mNj81ajwsn6t8!x^goACX?~UKdTJY@BH{jg?kC|m_mbfB+`dw7}&bZ8rFJvd)$UX zC8l(20m>(rhEH-#(CCYJ-fuj+dme4JR^T(CjL&;m$ojEj6m;P94EWND2m!DoLZOp9 zEj2_LysgyGP~IT|HbhWhJ5$OU?H-PAbYSF}qg}^s?y~Q;4^3Wls6*_MW>gVP4&1){ z3ST#iiq{6k)@oK{M9ZH8lyx?z^oL!34OQIj{-e8Jy0!C+=Ty2zUBQ@#SSdTzwX}_H z9gR@f{rkiH;vdzHxsZX05A|SOWT3dI94gME)9uF@iDuAy+1fnQs^@S6SUbD zft%mw_|brois4X&OHHvDDV>P{DE>@6%Mju;yh-v_ZRPEnb9wdX(Ic8|`;}d;( zl1@UoTZRTtSJwA(H-J<+!pOo6KpicX7^brM0WQ? zU0z6==Lk8VS0~$W?wTESXYaBwlKz~%V1JqsdA!8s-F#;_;+LX@_pA4<3;H{UdyYgf_XH&@2Q4d5*JTl;7p(Mbe~e>cnzvrB$@se!Z|Nz<-YnC-x5tTMPK^2jH?RC5 z1Qz<%JPeb@b&JRLUsfz3DlTjawps(Q$6TK;^g@>?KItgHIN(zn-k}yh&Q@nEhOO*GhSh)}++ga=A6^ zNeVyz)M^E}0R78G!{XIXnE!x7Y3{j))=szLIXOC{RO`P}mX@XwerQpG{4c3ckx6nk zGPFp6d&t~@w&EWZ4W)kp8YKrbYO>bL`G5Kk;dFO>yZJd1Mx>BFgaP4wx5NYb2E0PZ z1y2{e*lgszSXsvozLVV2Pphz{`x`hUl_PU*9hc7m_p)oubjg?-PIq9;v31Qcn8*jC zIySwM8#otwo&vSg}5)ccuKeM(Y(6FgJ?+%E#)S~MbY;>-Go^YG&aNi zr`mb)U2_~KH7gpjHj_x!l_(L(c_|9)qPgVeAf5*jSNx>=QptvoDP$?ml9t|a-N1MD zi-P#bFC@~KSR;0ozFi#6cZne-YlTx}<9~V}|EQ>6fMK0rbXY={<1M=TOBY1-zK|GW7r?Ga^M8k?N*dP70Ii?p5+2 z@?~=SU{fZi;%{^0&yvKk9(YM)u()0d|K%2g^VH0KuS^QR)Vc(ht?RKgP$QmlC7oi` zJwDWF?YQhj4Xts4R15b>T4{}Go?JQvl|ecy3DLU{4e;!dEDY=*kTCKk$JW_7N*=gH z2SdS}V%K#_SL-|aaXUT@4DB2(nHniTg|*Lz#^nJ`s-_3D9r6Yz<#E=qcBux>#!S~_ zm`!|JI4ew-AiLwfA7S}*H)DVB7dok-7|zTY24&?3*YGzXP_JhPT|Mz^1XvIbob+9L zSUnLUBI!P8$<|cB?aHQ8g6%(^u1>7n zPIZxw>YK4cz)2L?dTW1(mH%}F_`u!ywS0;$5_Z#Dp`?`V%y{`*V+ul4SvM>i^V>xj zsKNM4h>W^`Z^BYXh&*$g9uzE?F9`cbH84mf>@QAA#WZqI*O(8i>t9zo#7=ZSO4(L@ z0L6PZWJ8kKCIMd;=EM(By3mH70OIBANM_p-kLoD#fl)V@EXr2%9ch>IURXFmR6Ntd zfwr7dSs0^3X_}sDmP$otxEV)rt_c5Z=f4Xtnv)@IK5&@|b2ElP*|bD!d0hq^ZAKCB z%C6MN(c^zqRkGpuX0AuF_|S0SjN`d5g^^65soav_0b2ku@^#0qYmPGXzO9r)=0NxB zQX$~zHnIKAGsm3Q(E7ce-`q%uvv$I zW{a}`MJ0c%P|pjinEQWg5Hmo{7Ye;NXb7AYgJIuC!oX&71|>uIWI!o71#j3O?d))D zr1oA9c;tEvo%2~kWvnMkPEIb$eAhmdwkq}*u6_VBO;^@ZG$zS&L?Cl)GPQZh2_jo* zo;=*?@D73a6M+7{fA)K3075qXe`|$ea!KwR`rpt7U_$Gji`f@i7EC%&Y_ou@TguRu z{J>*%=%EOm3Jy*u)mJlMx~}BN`~`Cf$R(KN7-cdjrlNIU;P=;1r!s?`^rd`k;yCfr z@7lHfJgac8D2!(&M`f*_{2B+-U7SYVE4X!bsY@DjJ*vDrk=L-;AX!N3Z>sO?ZuW%$ zuQ-Moj|{6_vo}q(+z!|iX0%y@lU#EV*UHt*~R=c@5S7d z$r->KZ+z6@1ZB7+tT$DCV9dpN!Nf%cWR;>EnC3_`C2Nn}q#-a-UY^3L2m{dRR|XSBZyGb5T_STJtS;O6$m>qn@g`&b!9Qci z!aPljH6QK5GV*5ov}ba=xyzdF)JRdj?3xoEc;6yO*~KC$AB}Lchr~|)b(ZSg%&zp& z>Aq1>mFb$A46F)ifSe0uefc@UoxnK^M~iOJ|IXwjZKAq<=f7B+K?|KMe@ZNS<8KP9 z2!ny3@1ym2p|rmNM_Sqd^81(QH$`H@Wawx2%1gq*iItX@NHNb|CR@>_%ve$XlK&0u-Bs-jLe zN_d1IucMpA57=8xCFQQQ6{YMVR8$Ez*%aM_%j4kGP#?3sk^enHrX>ahNWG-EmAZP0@T5q&D6D-4I8Claq&xW} z3T?J81Z7o1n70XLbVZ%Fy7tF5U5x#;==~GZ z;%h12*%?j{dHX}&cQ%K*-{!X5Utr}hg_(+oMe@i;+X6D3oim3v5HMFC7b#16NLQ9gx3XCt zwGW9LuwY%Lh92ZaU!P;+^Bn z1fO7ZY8YnERrk{;kdC|tGI`}HG+51tm?@I?8a)X&wVq?t3u!7^N)Tv5*_Wbb<{#!F zoZqZ3k7M&)(;yB4Pjx=Kf}F5_t-s$e(?DMK>kKqwaUwXq#&y>wy~3o6QJb0;Ew0fl zz0ZRGsPtRVKjSf`AH49^S}^q2+xc2Bl9B=OxZjlb0G2A-4v{tz^LvShd|yddcC05R zJCGb1y>n&qX~jQgjAvd?)ZrJVPPJLIPre=@*L(Pn%D6(nDKHVNY(NfneLj+n^lyc& z_2&y&Ago015dpFU$=XN_9SW^xc4S`cZg>63kePS{f$G|jd-M(?RT^Vdg!eUXtc00$ z%Oa$(6O_mlhsLWsh!leNv-W>02CNm7l1I`*UjKDFG?pTS%Y%#?*Oq^Lg+$_-&s8o$ z>>&3uVmWNFb9=(*Mz-cThLEM=$*_pMKF+vGAa2k&8dut?~-CG?#^;MH{n)uCeCc~lQ zd}%*OcV(nk1Ux(831Bo7Jub*HPQ75{?=$#JUp@cDcAzGgd?r>@huQ8Dx9^fBDdcLZ zk<^6=#$se!6Y>T(4*U9-Qf|#V6U7Hs4HTUo2OCqueOlLu=R#nAEGR-k6FHKOO#_&@ z525?o8-d7V`L7W`2Kp8M#`h=7;?w zF8E>rD5*knyv^l+BMlz5gkuV2-&&NxqxVH$+ivNMQE(K@>=R*Qu7%) zOZxhsuL+%ovAk#YA(D1i4$H$OJ?$~!fCBNsG?^o5&D-K0VPP-q$tv}&Zr>K`RK9TDsQ;52BbKaXegCL7wZ|Tx3XwZCDVe?w z#Yc;BmKV)6+UwV@U;kgG|G$KvRhXJh{=O*-JMa{<2m8U2p*SE2{croHNX`;l-@ zL2LSoOqgr6R4mX4Y`LKW*E#>PF%UTQl`A5de`3OfRls)iVZG8=$oGr2pj|#eOdah6 z`E#^-<|3kG$Q0R^zft~U1^?F<7_x83kU=F;cxm9E)u~p&(&oicv4+ozsb^HQqqy_1mv&VxP-u(>j3$KFLgrp3AK>aQA#TdG%}Ze8c9oBl0Mg_yjL`X0qJ>e(W{i4KRsSMZ)= zWllrY%Rf2n$XZ?U;{~0QkojYY1H`AlCjr)tg6s5}5!skZGtGoQ zGJAidtR#hCn+<}ZO~~xc%gU7mMLJvZH^qFnSiUNp=h$86My)(CGTpoCjn|R(VUqJE zE<)n-eLWS?JxB3)6O}x=fV)+j7T>K(nfVM&EDc278q!y)JS|y` zyQdPcnfh}^dQQE^;=_7F*4KnMVcu--F8Eco3TjPO<#$y3Dml=$oQl(!!r?&Ogt|M) z* zAI2Tt71*(V342t1TCRg<8mmNH^=FHQNse-C2neJViJ8=?3HAHEb5InwZod9u=?r_p z`JJTaq{L{B@Ss+GrHG8Ot}6+Ky?xiM#5hRTEVm&#(G~4c&H3U-eD*UH74XT|QRS{8m}KQFtHe#WE=^Tn?A=9S$oaqJt$dK8B)K(8|L zS~}eJ9PAPNFTl_gD4u8p7R_MqA>>dA)9$n8;qBQM!+8N~H;VTQPpU{peIbg3U7*Hu+3l=Kk1ckIit1YTa|Q z0w%r^+5R!*N}r};EB@AKnlA=E3V$k;lqzYS8pc%y3l5M7Yk1M8_(fy2{W4*(C4fjo>RpoB0?2@JYqT3D1=Y}}5OfyBZahHVW z<~+AdJvZB{{!t}jjR)+-#Sj{=3NRc6@B6BJih90S!#>BT#|U!j1CP$|q$2g~zr9Ci z>#a;dw1o=gB{%=m-|8F_dlAMVqW!zmAw(rH;6bU};N7f`)n}CG`Ws!_A)n;fE6Gpq zESoH?KT>_Ju56Tg{<+}78g{LtL1NcBvbaAn?shFxVdvcTb)usGeI=DbRGa1MUnS8d zqQkclBafV>Dwe2t`&9JU6paxz1$7a6?I*Z$jegUWx|+Xa9A#kVAIw)&gA4nH$1}e` zl^JEtHk0q)$Q-W-ckl8AWU#~#Jc~0%2{1$p)d%h@|r%Fa% z9-LojcdEL4)rYelfWO(uuxYL4Zzj^U-+ud5<-d1r4o_q?hMOKdM)!%(kP~JNdHzwo z9pl$_ZVi|CJ-?-2AhglC(kcQ;(BbUBKu9qiwd}9jahCn6)w)II*0RXA=jjVplAOu? zE}MS){w81F7*95@L7pAy7ro&7f%#%;*k?c^*6&foF7D9OTUm7bxnLoua%2g`0bsmi zt2(ItCOGr<7Rp@v(HQZq6Q&CGkv$kxGvn7!Z?3pzt~&WB$1~kpuk@Jm6IgdnTTzrX-B#0SczxaoO_2Uc1&Q-R3*Sf#F7*tVccyGP}qW6rtB`dy?iO>fmA{Z&v-` zSZxBIKomeS)HA*>=I<&>a2Z#ZqRPe1 z)8=A88+*p_JNIWrJ9-4+=Js^VJSxTwiOvDRFA z&}_Ak;Fkb?KLvB^XD{98L`)J&t`|NyHv0K$KkZ(0p2fG5idFNAAJo+Eo_8dC{J}@l z*>v|@+fss>mpy*0=Tt&tVq#INQp;y(qNett$K<4HI#1jNO7Dtl*F@#4j^+pb$U-i9 zrm;O%feu8(l#b^6upd1pCe9|_T0KuK>grZ;^~)L)H~ivImCvk=%avfp%`v@idAMVe zmfT*bPv!Nb49g4K@v@{Q;R40qNCo(dbMW6DQ|1uOKQ!;<$KnL%) z@p8DjQtfjm-ng{OicVhRGi?U>&%1)>C3ycnF&(Of0Dh1J>{^ZGN2s!-VAl1-R2<-(yJ9kx&u5}N@Bs=*Unob*;Q$vCVZkDc9K=? zEidudN5f&{oCW1w1o9+KX?03giUPmD_8xoeQS1?VO*ylPvvO zQ43XHvHz$ZFTt0~Q_QQZzTAvewB4pX9L||Jy;@oSu7q-W!9sxx8COs$M>en zj_8%?RzLNVR)O?n4{32L=*%rNlfZokK%F2|&|DYHM>t zKQD-LR%?$bq-4b&El}(aJ}zw+!x)|^?Xm@V5*2yyuw@qJ!3HMorjzQ8g4Lo4cl_h< zIz#`W%BJsgIUf>cOrbbf0NL{4Tk?oC71rTR^V~Nvg$+e5MQ-cqCy(c*^z=A3Vy*Ip zv>}!QUtscbkFxh9`cn%bV&MhS|9$-I=f8^Gqmtgb8e-yHaTr|H{7T|b_&zc1w7i)y z-AknZ22kyKCHdxKi2;XHH5Kv|`AVjN(=m>Qg^c*`TuJWqYt*x;e!x(fM}lj=GRE#I zoYkxN-yc)dc=jfdbu_*(Q|(84VAX@R2w?u|>ls}`i((q-S*1Zm_vBnJbz4$h#w?2( zsAysS*>Ge-BWF6X>XfhQm7+D4}3m$5)V0P+Zc(=M%b-zC_L9DEN%_M}oAvW$((C z%5%QADr$k#P zYD&Xwi9W`D=$hmpwJ{ncg9#+-zB}(}z9Ru@kMDD=#)t_U!#z^SExLzSsc&_vDQP^O zEn!V8u?9~3+WN-&htV5Gv{zWr{(a}b`a0wNE;aY@w_3jK7K3hZCeEjiW}zGgOZ^c3 z>pczcEw#iJ%*nq6{N|8Qi3pwlu1X2WCD_%uKMG#rEp4qd@)D?OrHLub5zG%0H_VY0 zGC$9Nw^OsTY$k3LR1jXCgx_E5zXHvoGX~sFw>jLfW@fdiG6b6t+=a2=us>eePjLu|LfN4n#MuO+J0}$_%U}_ zq%}LITgOOegT1ij)V;^md^9tz%7!776HHIaw!oW@J{}5NQ}(+R%5p!lAI31&FF&Kw~Q^M*?Bx)PpKwOXG=znfjcFFp}*^@3UE)=fH(6$~?t3~}DgJ{N+K z*S-x^PR~vX{|OlUPzhUJ1S(lo7A@!q6#%xaW7G?ZTvM_S;Dfk8_*jt1*V}yW?n;*V ze_9lx@xna){W~Tw%Uq~RNbyHwg7`SF70oZktR0kh!K%`>8my<(aW%{Gqi2jX6jK-b z5b4{ldBZ0?QkVHuOz$NLXt{I+bmC>X6&8=I*l$l%&E~M)W*K~AJ-dumrwG0rzFBV2 zzhR`R+${{LMPCy>kDk+|Q#LcV*DAeQ2OqzI3JT&fJAPO_Cpot+B(5s zJBjN0w^0A>I^I5tY2Ria@pDk-srXXu6EfbuG1WZFj$2IxIc=r)SogJV6t6K)-X+;=Tx%o0H5uWwtFQPk&3X7^6Ak%T;C@_0wG zcr@(S$5QEM4n-Vh;#z$5xB`!WpECwM4s4y}hQ=SH7w%RU9R4Tm8y27m?~IiYa;FJd zjV~W(Co8u;Vu@TZf{EHn@5J%^W-qS%9d8i~Y?}#i%lN6qn4>p&39|YxOst8QXzXGa z1QQD~dvLt(aZ;1Zh&IQF`z7c;nYUj}S$*Hhqu{hzFNm`s>q~mc`SnQ@sYK0QghS{t zi&sqPxzkLy)sDAI{m($r7wT^ummIL*1q)> z|IQOfXyf;KVZ!F6Ql8Zhm{d;29AJxbCQEM}fOliE#6BQ}O2A)SbyS`_{vm8^+KEWt z0K1>*5PX6l$(*G;*r$8UTaMHG`QM45v4vX7*70+Bhk}#7jyF2vY)pAJ zI(pD@@i8B(=e%;M#q518HvG+aIBviGYp)qi)tc4E7nKrz6+qU1LekUal&JP$@Tkf8 zso+J!UC_`lh%dtl$PY;rhDW>jn7(VuY)`2W+1KRwBR>0x<;vetK)vEDnsJl-L+qOWbMmuJX_tsIn_xMup&#_*P=$S681?Ig8 z+NK`gGYVGMb@F`?=vhp~om^odD3!&ZH~V3yWNu-`@gEg~M}f28SLUF+Yz8aqB5|H8 zZ=^|W2M>m3Y$k56#gx_Ez~p}6?hR>oH*u4HP`Q8{+N@0Y6p6|H^Onb1m0ziR&@NqVgjh9>wq?iO?izzU4=%t}4-TB+{@jF+4$+J4$ zE4>ETNz`j{d*R0J7w0#H7w$uep=J{~C6PClUQ%&rNdErT7r+DLXB@E4V7_^GeZ5tb zBSA;5t+#Mt;Y$bl_uf96pcad?v^;Fw^*FJVG5Rwp zYg@b;S2D$Ctn8-zo3rVSW2NI(mevV8K|~N2sf|K?+!z(1Qz|rOdDQ;cZ$0UupZff> zroqT6@+JQR34jZy=)D#CP#dH0g^*?=3}=%^;Q``+$smAxIl%GhSOAYO7w7C7QNtWf zntxO>pU*+-E-C6_?Ge`KYAL@l8nq(fux~AcF*oMcRC3PhN29tquPglU%Lmws%~l%3 zt?c<@9)S|&m;W;k`f&O2+rk}M)<;`Gv)FvoSQJgwtN$WPutfEHFJ769%<7OZRu3%9Thp90A z(eQFuDM5Vh^=k$H_$FtlHzb)F`4xFT_>7^jr%G$!M_vy;)2_Gwi*KvE9q+R?lUu9t zgk{>@1{~rLbKu^DhYHZ>Qh)ZOxN zR6<1CyLZs5R4H*V-}olB{OUqGDi^d?^3e&~rg0y6G9%%%wW5s)!L2HyQp1v{z0p&% z?8F#3LS%RxKzg()Bug!z-w?1gOk_qHG%eMs+oSCq6!qB=(EGqss%^e3Pqf7nsllg^ zPKe_lC!otX)p+)tH44zt{8zR-x!lLaTI?j5?)R|% zgea|*=PYS;cC}Yd0+k5P8D}=2 z$bZ@_-oeAeMRFOs?_}bl2h5i!&yB*-zy?5-b(tX%!mhzSGpNDDTyRkLZf6jgBQ$P1 z1R%pVi?Ei6c}L5(lLiy2$RNsU6gFAeXKVQ7E-*4Hg3$R5YJ>rC&Ub-UaxD>IL=8BZ zj91ug&JV2l9;xhx{oSesVMNur0-nob93n$9dsglJ+|-&klULw0GgZHiaK`fcMn;V3 z*e!6FEA6&H=HK3KovrK`a(*X5qC}L=;1=?cKcFhgGK}L1{Rmcwmp$)-e4b?vJV`g* z$fI*M3G-5OWSs&fXM&Amff=yh2;Umr#-BBME6bg%)aIzAGMj7igKo9eYYr$f8)OG= zeXFl%a5)s{mS&gxqaW&v3*_;Up;8Joapt03CSwIe|UG+`1e_)R#QFY1gq zv6|NicV0P!*wEX4AQw-(rwATEEyQTg(Z&Vv+4`dAD97xlmWHBKop39-UOclG! zF3iq}Baq3nl0%VaoP1zn0=Q8X>KmKCGk$_G%seikj-0FzlPHfhEpFys-u*l z0`JPV@u4~!HGLP_9|`1Hh$Y1EmuRK<1HFVCj94c89BYz_-&xXZw3>woV8#ZK;GElK zjwI(R@Y{K=TgX06hz73e)qd{y3H=n@;!Y^eMcIbq)o-tEA!Bivp%g+J#`mXPo9;)oJlombvoH!Q zm#8bsr3%Z76&HBmDa2G*v!?3t{{YE9!K;!XHp>(P4l7(l^+E2iKy>R^VM(@VZRphZ zy3Sl)W^X!wRl2jnYa2Pp4F3QHcqW@G#22;q$jJWyB+^8t(LaJDpIFgIWT8T197zZ< z^lMWg!e#{s@W-2r!yEalZK_5l?U2Nq>k^DVDUk>t;Wy+;jpUm}BEX2|S4pN?hAcSh z+|YvwzG?peR4s6;6{1JqZi|F*wzEx$Yr8q4;_NQNP{uu7Gt=l-9-+)%gkNzwW@0u{5S?8jG6`y-!j9ETL zqvjMVu`V%yZ@|~tDYj``Ev!FqCPcl%EM}u!H7VQcJVpWQ3WUo{6E<35%n_;=#tMq> z)jG=-zPvN1B@p}c?MV@{uE66z$`!8CSvb#`Z1l|hOp{py8lH+QK{FJ#>nDwA^Hy6o ztj2MEV~Uo^?20|6g)hSMRbFzy=$b@?XnZnI{Lk6h5+t1GoQEY8T4K5`_z11Ng(%_j z9~2A`OeEYD%mxNnazW9%+9=KTY`}l^Qu!yu4VZIe?xO_}wq7^H6EMBGWz`7qVi&OD z?BSh1qPBS?6EH+hxhpha2rq|HIUMyy&iRJMgdW*cXntw7u;zmS*NnZK)4cHTQZXse zsY5P&{g$gcSl!SrsXggQHWP4dJAF`Y-Ws2~Y`te45V4QGi9;iUR7+#qSnrd6C{`~f z3bGgWnBE=H@mLvVikhCsS`IGZ9X|{<7r+y9Yj;$`bBI4R3e+0o8p?NqdCHC+EmM21 z2ML9{XuFazo^qK{e6B={Y$wd%x0M5$eV$Z!`J*S3S>H|auabZ-kHsDzx37w`TVV=B zJGVDN;rzmc_TdfJXYU{OR$F8`Itd~CnD6SU+ryT0MXzfb_Xqyjc~V`qryUIPWyLh^GT#T?g@R4X;wN~?JiAOH+ct~Bbe z!Shy9JN~oNU1ntnz+_RfM1S5Jz-UqOg^~NXjT}2Dz9vJ@Z)n~REHqkh4{KF5I(L*Hgxz}Cdh0-r z10`~yZp~T^?+~|ls6@{+&EV7EP788J32JOdcaA9C^*|v3lgOCxR+htY7b88R!O7do z?%{~7KJZL!>)vs=sE^FM^w>QE2V?)l04ERu00IF60|WyB0RaF20000101+WEK~WH4 zaecTI%J{HR!q!id-M~ zI$Rlj8R9Q(MsW2M!@LXx(@*-EqV2zlfR}fFaYgMJX1I^>06fkf(dKeH{{R_@Ll0sl zMYgonl^R~Y8AuDucMop!V@KBJtZdIG_Yk{xd~cKYDME~3KinpQ=>X(sl zdX9#Wgf;3zrPNruphjN7PXpie6(>-$Y^$U%O;wI~iAS8w&JM8kMZZY+hH;M3I%3hc zF`HY**)bUM`yu6Sy`E;-Hf7Ch!`qm(5qNeG+;v0oFl1OdpT;!S5=y4cJG)%g6}a6f zl}>j*WH>Z?{{Y1VyrMak=2w|sWjU5_Eaq9vv$V6cvU$%bZj%I37U)s}5C}a+od|Un z4_wdfw*KQUp5j0q-fiVoVoi8*S z0?HpRtN;|M{{S;0d#)ZKMejqfV=NVU$CG|O>%VQ~Y1=It4U@ke@h?K^(Sxw#WZ9Jy zs}~q*@5Apoirm3ptKL;`1?dY+a-iCvieo4&V7KUZKj4e;FT}jDEj%N6cc>BzXF$=J z%IJup4uf4Uqe9~XE_0rI5%46f*;<3VTHGBwLaPOt;EK80vcQ_5iHkIA-Y;zXCQjw~ zh%|Sc?P3)bP(6RyL8GAD72{9oVbRI?j@2gvVKXQ+<^9jZVci2MfNH%Dj(^Buhiz6( z-h2DXhX+%D#E@{cuKmx%4(U`|{P4yK*pBeCW7pHmsZ`W|>gCIe-dwmbOF*pjI;jrI%{DpppX`jWc)ekN$|u3NKZhcd4Sa83``79S;s1k+; z<9Jw`ah`ep+uk3~)OChzznZ}EM>i3S!Gj?D0JIi1WGyeb+@fO%#PjWh) z-_kN%Gb+x2igc=XN=or5#CWB6ov0ji#X*-Fb!BvQ3p|h6^8`hR0FnSKEzy6)0@Bmi zJ?37yd$QGFO9bF9BUP@Uz$7=&9wVvS1WMzm4k~kHjMiKZ?7(zt>A*~G?0MQ$m%w?| z?=D4lyCr<1x)diZAO;6S+H0*(Yps369WD?SEvsS@&hM!IW0Z$&oLX zxWidVNm)rwf_kBhzKZB{3$$w7?E$O^PyiP&-kbELy3pf6_QgUZ=8v?)ma^Aj9+9G0 zmbGY=1is_|6`L%+%o~}ZnO?emLp1`YWoOOG+m?QN`(=v#BPYWycL~`5?GFaz1#3S| zJ`Z_tbECtR{{Yvzp8o)IQr)UMuUftMgH&WS!~K5{t&CgqzwRVAO^H^6K%QKY9*WQI zlEsMopV*1dUEFU8yI=e=wPB$RE<7c=45$|f4DpXgi>HT0<lRMJ^rVaY+iUqf%58 zy=GcLhhc!X#7hHd*@!)%nVOT6^?b@g2(5$mj8BS{`6N|$eMWBAGO4DMnd%zSm=;B0 z@clw92B3d?dq7JPzheGK=wV~bg5iXZ7q`7i0J>wa?JCn>uqIY+Z}*Z{ousvkRdF{s z$qZ|3pjWdWD>^{uvLIVMvu)fLP%+NTYz0|fQ$yxFJA1(ev8fRFh1#!@u>D8Y$b2<*{lvt0I`Dv&mQEkyQ|-}Tn7IX4 zkf-~!F*`AO;_2<9PDnit2(CH36~<&ka1$0t1CE3`EX6UR^B9p@OcO%^4pzS@MOZWWk9(=< zGG=B@wNbAlnEPt@gNWQ=baje2>-a(_*dnkr8BNh^;r)e2den~p0Mu+klz21qZ)obt zeD>Mw)6|!rAv-Bwh@}GR=sX(xidwL%+?yiAU|o;2txjlQ1k%l5pgY|{LAa@+Hzj&C zhz(gW&-c{6GC*o3Ps9C1?4Sn&J|y^H66HIJvHiK;Dk%b;6Z+3-km}{%6Yig5h+9Sj zy`Q(lHdSl8x}RvYwqCcVl?|JRUo$>w0ii>Ysa>ej=0#v>ICZ$C9>mIPr4!kvaWzNx zymQ-k_o?$Tr#|ETO&6TS+o)Vk;lw=_HlzrN#--oohmD6VP`5>gsAC>ApMdoO_*N`?}ws$i$pqPHbKJd!AaXpL)d^9+P zP&VU8=3#nwnQqof;xHR>mMSOe2n_uYLz5Mm$Qu0r01&coIDdN+yy1uKUXe{@@oEiC zeLN9RZd4eGZA`DkOv8lX$73+)WB&joX``7*;Wipu^!?Pt7ojb6OBIC4sN$SlqsjY$ ze|TN?JiM^;2B#8@!lD zjdyXxs4P0l9`d+_G=Y`;6*AU-0DexGYJ_Xk33Z+LNvsD#P19V)Y4nCzF`AMsF_@0v zi68hGN116aXw|vzU+OH>ap4wR?;{gx6qlwLgAjJdq@deOP`wbu<-I}>H8{aF(KAhO zHTGnH>-e729w2c9)nAE%I8z13W}2#YgYwK_fZ|TtQL`=}8gOU}-E)1HgAj(exVMZJ zyl8fUwivieFL{(IE_}dqafgQ$iEc{2O=2gR`yZ3$ZxAz>N(+ibAbNp?)(UGp;}&b0 zCX~@DBY_f@R=p|z00djj_e7ePhte`bC1&%8qg!St{sTe#jy5p9M!zJ<8EP>_*>P}P zEVID@L8(!z7VhcxKv`c0`N2>~!sp^X!{gt+mH=%-GSP zruwXZ$y6bGSK~nPLd~gTaB?!yWHt$mxt54qX&8ee(8`N6<#Mv0y~R}(az(Ij?<)ih zyMmL-Sj{s>p%*V%ZqqJ^`*50wk?J!c+NN}3@7gV5?a^i{j`WAeq5{Wp-q74&V~oKW zowU&}Q^lVs)r~^O_1#I_)H);>GP`jW$W#HlQ(8ohi@rhlK z_=ip=Wks!E24+(@=r~J`g@zg3mn_i|hL8s0@rDwjY>82XcE=Ggy{3+p21uL+tZ14G z80kd|h1KyGb!mxVw(RdThXC2;We!c+1EluMaK>>fj`F#SITUuw*i7VH zrEX?~yD+0snxoJGDlrhur3`u+Xn(ts(J@DO`j^?T(on@^`<8>m$&*H4(jFyvgIY{X z)|+WcT*8e4y?OY5QU;&7ah2DFWM9= zTwIk43^4g6ve60%Y%087no5Y!jh=?^p+()lu4A*RLL?fzR86}}?AK{!wg5alh&v#- zoFqG7ttC1Wo)vU6rmkOEixW>nOIEX$2YZX&DIZI@3)p|MobhIK8vg*#+%_FtW$B#X z_oq&;L_#cUEg8OnHDYEZ#5P%;GkAz1*Pw$^5QL~PDoPHL`-l!!VQ+6l#*FC59=O&>XR9<3MoA8n(t@E@PfkgQa}CH~L{taSB>s z@>Y<}rh;>OB3)|CEc%8FLL72I%+!=z%t{QlvpptWZvzppcag7|rg!>H+QSf*5FI0p z$*Y)9g>wQ@CPMkl{L7~~O9Q;pyhU9?>msX3g!h- zQk90*Aql1CE$Jx@f8uP)NZIa|3#;Djq}zK-7X~BU8C8ru^X@@_o)qoLEKbHU*9QJ& zxzJ@=^4>F{n5HHiL!nFcXvze0(G~b3s+yK7Q(DoxHI`!YNlNHcL8}XqQ62;fDq^?x zzlePHS%SM6ra4Dlj8X)~dqn4gHQ0XUH&nZa`GlJEZaU?Luv1!u>T%ns zcgcmU3AqPIt;&$D&{{RqSVvoFae(5wkhI-1Ihy6(=qAK85}TV3Bt32uE6h5BPLOjd zlUmZij>x= zW>nRZQ!P3R2|FDTOLnk1sWaB7fl;}GsfJcLmtJQ&VY|a{rHa#JH4zjTM1sk= zFmxPKq7|x0@c=0PD-?rMGYhU@=3cmgYFE=X?>j^aWZH5NOK4mWnM$(yWBr}LFJ>bT z<>4`zgrD&t-O(ci^MmFExbYKja~N=5BNs=RdOk+7h4l`z84>6mE7&xB;8Nw5b}yBw z0arFKbYowcR6ENrTo?#J39~RcgcQ2Wv(Fq(ELN>#)&zbcY(ySRF#L245F(kV=^zVOzP$7tovYyc27DCfJK`MBJYY4V2Td*{Pu1w#UgSAQ^;Y=Y8 z3ze(5^1odP4Z7TxyEcvo7cIR|B?qlkx?Cm7%zDZS1;t z;w6!^I;En%xFEyjUz?by-4AsslZ+Wzjg1T19(UvPl;N!}G~!rOLrA7g8nU1gtbo)b z1h6w?Cu0y)v$V-Lm2%A+z9t^rOXhXfniGtoibNEFOEK!_@HEGZqG z(@jkbN-GeCB}S0z5x7HF3WzNa5Gd$Cmaj;z=JX+CQROI=IZ2z}kc;fcCOJ&pxr3mQ za^qKY0!CdG%pmm2F~2k;JSY-}Ns1?|4&E%FhKN-}Fi~=|Db;_H!Sfk5Wj*(rixAST z3>vDMS9z!7b?GiGOp!oz*~p0k+{GDJFepfBYdMgBl~}b_lM$#!(8gs15|rH#vv^9> zjO^A^8Vn;oRy<9~biKnjF^P+FGaO&0-BQrzxN^B5R?@E`=5vL!_vCIil{lv0Aygr3;=dvVwqS*+MpJ7W4lAxtOm- z9FoU~0z=_D#Y|E+R&Nktm_&t&Ak9>G3m{FBSVovhNJPWP?rp-nwNHLMG=-WyaRq8- zS>XL&9x5AlpO=5NvQSXL)ZE@lxF$E26e(}uxSiuLuv6MBI zkyANztiYNLOZO(Yu94<<<5mK8CV<+Te(vwo)uX8ZX7@@Ts8Cs~BwWdE7c&+L+2M=C zMyq-v9>bY~NvVmEh|YvIOFiKiTBVM0=8P4oGrL(2GYHi$tu65=EKKFbTJGytPNq%3_-!6pX^^J2zDjBK{RiL}9GUXQPt|w3>exC6Jd#a$^g}fNdtLHcy}iM03NA=_SvEY9yoYy?}AV{e6b2%!V)lQ zjJ!+j))6>sE@J_p*D1JMvEqYAn5TfuYMlmYxTLV`$5?fSnc^U>7}qUjs8G1?D#jKw zhHX*l1;pgqKe?gkD_}rZO1}{adY+&@2nri{4jGHN0}Yo1-lGOtO)ObEptgU)Z?-Lb zL7nX9e zYmx|5I&H|v835qi-9W}0fD5#+n!|2TmS9D`(>tA6>1p9-yxy&{H3H%SK;xmMhy+Cf zWlo6VredHfCW$C9E1xo*ui>dTRhoJ%GyO$gR6H)^jRtiH@kS_JcxLV2pK#2yS3YXvKn* zhcsj8#b8<6ff}Ycgp!4NsQk;5*lTqn@oqef1M@qjSG)seA10F=g^(gSWX@Kxd@C&_-FKr@_Y}*p>6Q5YWNItqA>cxCYP4?%sEKpc=C0WLU_`cID z3`puK)SM7HksTF^{@_y9>2lJX>J0WMDve4L(gup?jz<*Cqt8ha2u@&0xJO-wMAR9d&~`^A^0BQQUQ zZwQHQkhEiz()Z?8$JL~4w7C4h3*Kd#n$VUzW09riEyGRaFadMsV57WRFE=eX_=^Ebmt!d!E{>Dxt|>yKx1tF_E&dc`Qlj4hXGU3`JBFG}z)CU4W}u<6mi9-ZHv; zX`Qr=!d>}ITfxCEe4A7FA{>y~(e@)@Y=x69(S;{E9zI_aZR1pvT*btzG@n@MGam!) zC98e<0C(V~^eHu|MtDIG&W5SpRE%&9;v7Hg-Q}8^k^7SpYR0z`DD524-fNc2`GN;f zx8^h-KbZFRDHIiG3xip5s#H0P%v&y6#fh6Sn5twZh+38Uwy5F4S(WdOJVDqrBt>*6 z*hN4Dj#dIN`bBUf3+0wkz7!-UjYvWa0k06mSEr@*BHjvxHHB623k{P#^7K(=a3L$X z4L#YX2CEHv#tq*DrMe*o{iVp%1E~W1;kSE+8ZZrfc(=Q(W?9l5VkU;ThF&d_o%{KQ zkU&-(Tg3h)$Bp#x+v;~%4JRZv$4x(XB|OvHSzm3n4It?ear&qoWu&&ph6whdO+O&O zL8m)K{^g^gUl(}koq)`G#aNuItL4zK=3ZX26NE-hmh&>pX6V&NHLb~bgzB4|kr<3e zh%O+N^h(W{WvpF}J9}vu!NWn=znO9}VLW%~-ctvJ3#;(THtD(5S=ufPdZ%+_nSl06 zgj?rumdK6`@%SdRnArwX3mxa?k(jo#Z|C}jb_81&{OYf$Wd<`4-pj>5EW4l)Ag_bW%ajG zjM26iR5ch$W5_4$_k_J`DN!|90dN!LC>3mViqV(wFGF|~%8>Kj+tx5NV71L-k6ESl zYxn;Ek=mu11=+m91eycp6mt&e=`j;93*>o)n`~VF0GJ@;GL=Q)DceWP2Nfsnxo6}6oIN$A8p6BK#R;q8YTyy?K;{~$Dcnz2-Aw@=Jf4`dhA2sO|J}O!$SYEXH zz*zi;vAZxX7|ZRspDmVkwYr=N1$f!KxV}=u(&2{)8jS#yZEl8>FSJ!F2OCEr)lE&3 zJ;M!8s!YfSv18E%u^L5*r=@dHW8Ch0M<=xlNY}q}e=!dswN-yO?NWp!HOqTPMBBm{ z<az1rF^B4oMrOEyivvMFGK)u3n*#=K}nj+H3G9Ofy5@LE1$E{@G%kJT~7 zBWj+qQxS#v*@G648_c>a(^E-oH}AB;5U^=a5jsetb8F6z5XxW|ccS}i30&1~k3Y;n zxGX|^vF#c52O56{@I@tUnh&p7Lj<2H2tv&AK(>60R*Ap$B2=-&gSnT9_$uNy@podW z6rDw(gTBi|7e_G+sr?#1h`jQk^0VtHB3dH7ZdgGk0o!AUMHW@!F|&x}=)IeQ{%iw@ zs}RSBp^Yn#HL3ABBBQRa8D;IPVlENL857U$VZ8zrH1Cz>F093_tHYzkRH@S|6<3g{ zW|~>iw|3#$8ZE>{wTeFydAf(Wevep7O5KGT#-_n!`iLXmNUkgpzV9ap1VjO%`^#fk z+1&377BVYQ{Y(uel-K57#+sZ<%bF%AZpE?5TSKJn*-yzBddr|Zo8DzCs7KD)*Lbxm z+}(Rc?+-GY%E}-aJDUFeCJKeUgGL)B?Yp_wTCNcvTiAHdXm?N%?Xd~{er(ccPRzXm zu2ijsfWO3NLYEltsiiNLvBz^L7l7yHHzk$3cIVX$nqEYQOhQg%F-)FW&f0#-ug&W# zJY`(PbT;MN>Tf1yBGd9k5m$L-DRMd)qG{?{(CJ++8inFN2=-|FRCNVT_yxwwpJi;k zU2@iaPy16#iC-jRTo-6a(F{7Qn(rRFxR-}QlhMMqmkRXi}| z5R3TGqxySFj})Pt2wygFGxefKdvKX zHU_EizL)~na4YyVB_)nE80k0`uHu(vix0UV;y-OQ<=&T)T0EnnciKJdUY~gUC!#|dt*jpyj7t`v)Wiu3@*gF zBG%pgVtSISuyecXEkkwx0F11VqPFh#(gJ3{_$xg(@hJgD1QeE6Z+I<(C{hWPF1Fg^ zDpOKQ<0~7q!f#p)dEN0iMY7zE*C>jH3Ps4RseUX?9y(NNibA+GyHee@V%YFk^E%St zOF>PZd`mM|)u9YA3m9}4<;+6Lb{22HX-7)G$2IlVRv183XdO_+OS{eHRv^SLEa@l$ zK&l5)yunJwo3-#E?GtxL>Jsi>rlE-O@jHPm^H7c4#%*^BwPa62Fxx0HcZ7EWu3Z$< zKO$nX1@gus6}3dkX$Iyl(*=pNJI*8mGl*qJf)iO&5SI|wsEzRn3mI)N&(**6D-oMC zHqn=qs}$Bb6%$;B9?UV6Ifbe1r^fhN&cR_H&SgA1p=`y;broNNJf`wdOQvai7`LmW zVp#kMc7Pwg>W!Y`3Owte$sOws%(JVmHYoe97T=?)&ckC5ycHWop$w0wv_6rX@t4FX zGBw=HD1HEO`iR5fRy+40mKp2&mkJGUZ?rliL0n0^1U3pZs>ODL391n)RuED~YUh{R ztG*FPq+AqU-`{a6+~b6y_kp>u^sU1ooPRb-Kx~!&05%~v1!wesQo0&P*0T^|W6ZFK z@o%s`x+9vKV*NoK3#%vA1T#e71AbsSU?4b#U}9?-Y#>uH+NNDoc;SNy7fMvmyxvF- zACu(qF#1~WvZX>jE&-ISGyvwNA{__vTyPBUCvDlAjIao*`U@4L9mFVjnURNMgxUFk zyA2I6iuLaEQn`(K(DFuLXT5f%3`tBD+WE}7C_4nxbRk?sC6eXE#QV$)-yV%K3zmh!njXRZkcov< zcK+0UJBOWPU(g|Dd00PYer3UVvG0t^%I@}*@<=_B4TiM!CF0a7KM+sGvRKKm4fwGy zExd7Ubb+q7&QO`0p@~Q;(~=!dBQ#0`{J}mNnmZh>yLN>PoG*PxymWK}PVuZ-97ECF z;_4FnMVzxn%9fyPNb*15o@H~~ppXx3We#4RlB&lytaU4$)l_$kEcbW#z$}%(`}{#@ zoxI(zjXTU?QNw5M4|dN@KhPz?LxkPs9L_m?;kA%i=3eaDu1+RrUVTV{2zOxF(%^#h z;wH&>=(h1RfxE#0z^f;p{hRj9<-g(V!Cr$<}{0nlr$5rsMyCC5~`Q#3#z=*6>iM&zWfbklif6&63AnYk0f zYAEOy>4>mR0N%{}<|w7vMUJgFNt%vJuSK@JmVL%p(hgu7$<-87=F{silr!7%{^OC7 zEiBq(tf{$)!IkD{BrItqrJmIpdMMLvK3@S0;&^jho!9PD(mK464e#lIpz_b1MAPszhgteGH{=MC*mnO3@y_<%L&6rHS$CyzD&Q_ zxP1u>@p~j=ml2Wh_m&_OYm8UTMnaAX;B~|RYt+R*Fr1wbKI-Bq%a||)%NmQw@%0#v z8gQZx@oE163X+(UM$U@6Gm{J=Ias@uS0Pv3zu%4!giFpHm>a^qf6Y@R!MgbK3))B zxo{<4lyu0otQ<^PTtOz(*bXJRU{RoMd^q))ShXr0wh^ya=3Z5gXPLL4?J`EFML+WK z@8&;$;zVqbSvO0?ODDv7kFBQ*Wmmi(9s?gjSbF~e$UHK_cCU2HZ8v{Z$kz%+3uUH8 z>%=f9DG~PQ4mz$6GgGoChOT8{T^S0x4q6)YEKy7gpgBBUe8BY_?jN=GnH(>RA9;R| z-E1z67&ieAUWBUNP$u6+{=fhtnx=?#xHr%m|+4WiJx8?i19uDp5oj-Jy_ zmyy}8r!zUXMg#U4myu6@-#&!Z4ug;KrAuLzhyAev#agJ|XF4Rt_fr7?6al2w&`T!I zLR`_)r`17Fk7W^?0AJ|WtkW0^#mzsAu-*cEXveFLA&_hVq|oHca!}G0iI}*xl<|=4 zN*dM$@;{vCZ_r(-X8v6YBo?V+@H(+0%zZBE!h(Qy>r+r2Bx zmK${L+p>M-;1Fv8YWIe;%b~b$FipUe)D#ecXqr0q>c^s)8H+d&MIN0u=oUkmt;|af zCl)2BO0`SO8finxa^)wZ2-=eb89l?g^I;1Eae-Ga&q^CbQcbub6;seVq!#7T&u{rrgo2u@s*=s=&l~jYtkvE zf;1<+lgA0p`3;Y?fuK-V0`YI-XpuEbG^vOaH<45upUvNl4pA%Gb4%}6o)qS1a~NLA zX~w0*7J(%X_~^k}e3}SUd-4x+Ake$$nvEF#R|4A<5<_#|;LeZq!KEX2RBSXlHLr|- z%;JC~tzeEj9x5Kr%h?i2yvmGe+JF{{TK5boG)d(gb)ith$qbcDS!^ z#ntrigxzLO^_Ivi7+f))tnS)_moi|{_AI_e)U9c-T2E?^JzVO287rE2PK@CRDBFEz z%t)*OVJ^Q&rn5hsdOiJRfGLjVj)c+Ij+B4Ss?9lsH>(MpQ8djyT!h){%@?&G^=7xx ziS%#%S^P@ukO%B?VTxu;Xyma|z1!%6)6ikqYoYKzkT^E+cX}r*AR`CN;XEe7&er4_ zbSd|l`acxbI^z)FFy6;G9`=s5gBttLdpDUD-8!lmG&|FFpMoY;VM`FGt_6ff7zd}4 z<3Q0LrpE;(#_+hzypDfrz;75)EcoT>SOF^LynN3n*yW*smf1djQJxrHPJ9aWY8KpQ zitYi!lV81L3fW3vW${D!P81HRU52p40Ll$B(N)5ncnE_~Yojefe(y5;0e<7(>x>Sn zW}BFxtyu_cOJ?@ffwoYI$9X~s6qepypLHTrZp1r@>N%&kEhcdL;(7e6BEpO9 zOv8glwMLr_?ULN0Fbsr(7v9u>iN2}C;o>CUZQq*8pZ~-FC=mex z0RRF50RjdC0RaF2000315g{=UK~Z6GAc2vg!SJ!s;qfs4+5iXv0|5a)5PF{H!8DUR zy0H8hS!aWb9|;FO4UD)Ci9k+pYcHTLf-F$|JBaTeypz4$6C`G3w*LU|%OWB0c;xZ9 zLoZ$d3{MXCQ^Hu1MDYlgcukWd&ScLF+ORu-^j%Vy)5|_X4;K%B`pdlEH>tdMeJ^YM zWHfhgAG|n8h~B&fd@%yWix6bY+@kJ1L6O6eFDFp8O=jKCnC|krT>A z+ikNufVe~QXUs0VrHg_?7)Km3P{Uw63EuO5ZVR+TCUW(z#A4@2a$gnpM*6jVo=U#0 zo%p^Gd$6?hL->c(uZd@?B4l;&WDExk{Cqv#Ch2C$26*eqdGgzO+mjm%*FKYaqt$_{ zaA6CRaX6M7X2{vIgG*Z+Hsy&$&Yz`+hS@!c4!n17@Q+rdUfTo59uCV_2F1N_!^$TU zZpKZMI-3lEK1@6%!Fy3~{+_-!>VFga{{RqDR7uaK4XU$Jhhx7bgpH% zdVn>nnA@Cv&OJhugm>WhwJ5V-*=36m7G1mqE>@sG@e<}7Cs#okOdc0E7A4qSz9$|;XBbB<=Mk=N zLKWufdY|0Gt0xPWGwA7nTiVblEeWuEUo7NLh%bO|7GVz-AjEwV3>hLfKg~X4TRZFs zy`<23k*^b*mTjIA%dh7KZ_W(ccZ(uXql-@BWGUx5ag*P zNj7db0-vXiB$?z5eN3AOTWGXjD=@a4xh;p5-52&xaCQCe1#oL{5>#Y6C$7leXONc| zXAzRZ(-^h~OOtcH8#8R!M~@!^=Nh)zoIEwTa(6yqrO9QMcsPZ_8L0#AjSB zoR)>pnBxgSgF33p=4sh>VtLub9okO&@Z+l<6<+O1pCs;9Nvz_}n=E{fgFV1wK=l#D z8z9J$->uXi2_OPUkBte@*Xo~=xS54bohF7+5p!tV(1bgY_#jIJT`U2)IbbowEkP^@BcW$@cx0I5c#vhTVq8xr7c-0V8`*7K z)5kmp_2fED!c1VXFQf`)6^wS%h`Vrd_Y5>RGTbx>&kg-y`GPvr}fWX13fR#puWH3IXm|Wb)k0 zfJ?nYClqIU0=Z+uWGXe0DoD0{y)U)h&V)bTtz%#p!_iKJhb3cMM zXS!(?B36_=F6FUysP430!Q*7lddGQVlwCa2>{{H~v z%f22dT(Qw689JVesc@3E*@sVv_Q_yPm^R6oi)X;`Jbtl0VZF_x8JtdV4;4o@qusoW z0}qBYmT!I`I%BM|)CR|8vm}H)N6iR>apu;IiyNgl7-twxBH-OZO4X8|6fkEt4YR~Q z7|t%~?i|FPB^w6M58%%14~J*Xz6YCTF^r6{8OzllOp9}2vB0%;WOn`7&c$43`dmFK^xz3h66V#YmA5daUta)xrbDJwvXKsbDx4Oz4@oa3J z>Ns}izXM*UiaU~D!08Hdx5vAR5rpu`Zjm?q%IE!j|TjtjD5gNp(Y$Zfr! z7{@swg?oi9L+v~9frGL~MEJ1U+z=YssImC5geR#uS;HF#VrY%Wam)pP+)3Sn18DKw zNuGFVBbo5WcNXNy<&m~e%3QKpUT1cdH>Tix;TX&z^kI<>HuYTQ5zo%I!J+&BG2|XU zS8i(wYdkjiJ(K2)V_tP2fWmu#G1eBKAH+mI6Y2NS_7OtA703|(wC1OwA+ zUzu1M+xNsoiYsdHFZLGc86vkQ@FF;@h+UHm!37EE;} z!HSVG3rEEX59n6ggf;MK7f25#JfN1%dlqSQ2ccUPSnf!H!EKTts)nD0gPsC9beAmTzkh42klKp7U_= zgrS>)`a?(3!5?%fXKLqA|IiH7MD}S$g)wmhp9|V5?dLTbcYaRvgzQ&x5DEj z^&@j^Ibj|l`kt!Qf=`HxEwouyXb+nmfII7_!}=K9YXM@(eaL^y^Uh@SywMv)CO<~j2wd}yFGU>nEFE10vfMsF2o zF&jM?;@LgJBVuoE25)fRnaq6MjvDQmIJRvJx$8kRpKXZqvFe>1viBms3gO!UBG`2u z%&@xi#U>LxGdtw5=?g(1@EqYWjyxN%_!i6B!2*&n&OPyD%a4a$^}(<0WXsc@Kgdd4 z*>WfM_ls=5W(!Ck->lXSPd=_GbSGW`ta?h0lVfq0780DYq}kQiW@ehewjYV6KWmoF zkTLOi^3fi|w|Nxs*%Qm)n;^{xhs5%IID#Z08Dul$7I@y!%^Pt{{7fI9`&^mt>Pf{r z<4$kcM_{>LV)5Mg_Z$x~=G#tVaqn!6g;K%I!L~8Zwt24*^#9!0)(SOfIAXN$HnNpy4Ra6kvFi1X^rIh!NS@SGSOIzF8L09Gv*@4xOx z!hb*a0>U4k`<$2ZasIdWvDi#7^C;`#o- zA{^Kj9ZYUXpL4%+d0VmbN7W*5!Z^og#y7TiX9gZ!lRL93#(J_|OonlCd=r}=9_ir| za;yg}tCM_79(H(Z9wl{mXN9t`a}HQTF%LJ!;_OB6moje22Qtk-_JU+%7C9K^*!ALR zZ->K^!-R3c67xO?@Ou0oc3nBl%#)7|&LySBBZTlhG2XkIPk`@&&kv7FMoXIPLDku~ z=b2)X#N?BNl!n~sO2(A7twOtpC0iqQgf7XS3N8%w2ZC;d*)RzB4?1{Z%&w%a!ywJw z#BWff8ya$2wwR`_=U)R`Qq6+n6Xh;q&V7-_SvYb&5EQjdxWZ|uYv9W>#-qmEmYlHU z+?yoX#@jCi{31K?HqU)d895wg?LH80U06jUSTX`~BeRTkZx+vh`MVcA!yG1>cLHoL zP{%J+opmeAFl4OuBb<;4uYkkP7GueBv+;e(TX?oSo~`gsE>p617~Q+%3t8vmtF%jr z!=>6m%VPRi9Y+UYtVH78ob4u-7c4i$zc9%wn+FI8^4SZe(q0XU+O)RM2uU}&NMN4s z(7js_+iw=b1;d;5@tF>^kBo7&=6T9^_OUBv-SJ7DWw>E!XM-VmY|glnv^M&VSqn9I z9fzd*PUQIT0eQWPhZi9VZ;J26>=p@O4Yk*E%g2M&z6)*QUl8KzV6u60VfnmreJ$0q{WEaF?=fv_(I<{@x7 zExTOXfv{V%BJF$60fG-6?$+@Q$g>I7ED*U~Ww=;e0eld9gl)rd;qW^H#lTwg46-qfX@NQWyu~d zrH!IY|V9t5z&zeBq6UO_MJkgoI26Y$?6~n;eBKjQOjrT-HN^>yX3v02a5&lf-zJnAcE_?iOUpvTTA4n1?n+YH4d5E@z3)6Tl-U zz&69qA@)I*YSzd*GwEl-YXIARJO{+pfqTqjR>W~6FSV>E2|1GE+|OiL*#umqxbY!Q zAQJBPHyI(Uv*JCH<~MO1L~CwkghRV8i7zIWIIwdgbtx$g%N<(p#hmoyctOn~zP#kr z%nm)v#6~*~AD&&CR41s1TQ=h26I62KT)kRxlO{N@gLs2AEb{jd;M|jKbjS5F;iteL zVnxeBJF`b_apDg{n_cV+>cZGK-vz~q#NrN8qk*}!-@vos$qbugn^w~i#JHIl)wUxM zg~BCSwyw^XCLdqAdJHsWcI5*s4I6N))w#8tIGhR1(!?6W z)B&=Xd6sD`fI+&*MB;0nacMoz4Vey4-V}SkFfH3#4@ahR-IF-&IuE&)CN9x9=WaIM z3x3_oYZ{vkeFRIs$Ef4y;#IgM;_L4oK0R2)?;g*$U*h4!aAZ%6B~uyAa%}5j&Ywwf zP1pR|OS{PZJ|W~J6mc`b!c{kmPF7`+n>SBVoX@z60(S8%;&9TNRH8J}C0L!Qszq}kl_4M`X>T3F2CAf#xzr^>0Av?5AJZ-V$ z$V33O`nvxBH#_T`edk6*{^9cdAtWDH5(;ond~e!U$0f!{4qQ-KH!p%dY&^U$fOR}0 zcEPjcZUSfxAGN>jIGCLxy`kD?7dF`S4t7b=#hc6=NgcZtH>_s@d%Y4vPOMGw_M!VX z=Ft63jQEI6=@0P>9MZ^ccE>ag>}7R$VUpNy<^KS;e!kZ5(e~qi!7jIc%;EjNnA8Vd zeXmJ$p8WO%ia&cSS&JQ5;nzF;=F+YD`~08mjP|(CpTGXyFPC5YD|lU5b%D0qMh)mO zv0zJ)KP#~ViDw}&pOfNtx4;`mw7J(8Hms$M;!WaULM|)ag2K#e?&NU^7(2@jp^kQc zk}<=cH}94r;tt3(4&k*9C0c2MWev=&P{{UMBhLgN;w_)Uuk!J7TnbvL``Y*)GmS+$? zB+hN#1a|{GWrpvIJ$*;d?=-mlkR8kLcO-oPN;oNr?%0kFjL$sEiho@nO<` zD#W_@Ho{Z8y8HEW#UB3v1y$LYtZSQkG|zrLiP5cguf2)-PcNt9Z`9dq1~%k%#L zAj8-7KIiiwNctPHF?jkj_S;f$_x z=hces5z<859&8hr=>tI@ty(5FBZ%B$(L6UOhVvX2S_>lYiJ!H2R zGHh=w0olQsZgn%)jR`QdZo{10Cg_EL829$LXz%U*KbuAD`j7R86RuoG(>jMVo8RBl z=D~)ZGRWI|n9is1H%u8m!F|*w25_@)b0UnFq56`)qqo!I749v4@g@6gN$|jJ-xE0_$|ZNiLF?$1*plTVn2tV2c{(<7?kGWp+o7I;$}th?L|v2DfA zBiv#H@ytVi(;<17ewL%QSs%BZ{w%>}{{UIEN%nv20}Uz99qcQXto!j7+wZb}9^X+- z&adkk%)wCw!gU6Wle)whPkm!orS{?swn*#PSg9 zzHTxV54?-rCx?hj?QJ{yCCkH!5j+5XPX7Rl;-7Orp%3cm2a6KEY&IOfd!n*`dW#HL z^H);c^=H8Zegf~4yU`YHvG`WN*x}+H zPYOux-;OPH{cNh|PT*F}Y4?R8sB`rB{XP6bwWEo8_t8A?5Qg3d>oLIf{QHMfykj3`NLy}otYQx@Hx3Q=^Bhnn91Q9 zT$pg5YxL0OE)(YDvyUOUFa8I2Xp6rC!{Eizsr>l(stXJ(J4oyR-v5L>oQM0lXir!|cd4 z#;E$dAGXQ2uKxheM9O%4>-@qCoX_Uc_YjQ z{{XozcV(^Hb<=NpFmm}}y~WWKoU_Lz+T+`Kp5d&qIT;4CXhysqPsBYepC^Ls9-)VU zF&;P2S4}lHK%D3Ol>Ircsr@<)ZE1P`9F`0p`fnKkpV zdxpbX@oao8-vK3sjkH;F;9qtiWb$E4W6Ah8z~ivbMEAf%$aoxlNI4I{j!!FcVb9O0 z|CSV+}&HgA0_X{md=}UH^7OzpD`XiE(O`(>g(V{fAI8|87;YU82RHaVs?pXG|~eC z4a?;Tr^T`4A&ukz0B!`mUeb;^^Tv;+q%{ha7~%YX1O`zfh138}y}n1{n`5gRt1hnPeQb5LBzx z%a49*`C@)qWATlRkz^c_)S3PVVFvzek3PP~$KdvV$j{Au`Cp7IdfW0cO!9SSWuF!q zu>i*QV01i|!^q5cN`B>yiT*5Xv;8WrG>jZx9^rSZrFJrCHtn+!acvzxV{a?b2qN&H5=xNjRh zSKi{0Mp5OP4-uLT$aj zF1@llWs{=(2~#riEiOw_oStJ2duj29u#d&gu-?J&&9%b7c3$!qWVO;?ss8-l=jYKZ zI|uEcuNfGfT^|$4u_g>6@d)`FB%k8-V%xtrEwzTj$Z``tZJG5Wag5~FmfqRBIGBF6 zvlqZ+xNW;I<&iDLkuF|i8kb~wY0sf2?d*SkEz1QMhi(}7HGV^H#(dQB)u?p5_!xU> zaJu>L_{FsmW3sLLK;d@b1O2@jj8sgNZL9^JyMi(X;B* zK6ea_*OA8Zx)1|Cdh*MX8yS}jNe5sYxY_VFS7%o_~R?2NddgxeFzc35&axk({GSAHOcq12@zD6A+`a_+#atn+pxCj23h$V?a`3( z%x#b5{jWa+c@r?|PuXdH(i$y-eCNQ4&yNdV+h2@%f9v4#bn?;(y+_8&EXZtw%kY#x z;CT(QeUv2~k~L;u*#p@_&5y}{$uW??eUS%jZc5%;Jek9mPF`!$mJ#rF@?L!5%Wq@P zo}t4n8CuyKWBlZoLOd>6U<)}HzefG}>G`~DFGMyS*db0s>Uk0}_~H72Zp}TrA&DWE zk`Zp(@W!8hFJHbs9{e2(gJLxi{`E%bOaTl&v+}a+^oz6eKgeIDsoN6J^2XdekLevj zwh#}?@C();%*byTWG-aC1RmrN&&x^w0Jx`cQZbk3sQL4Qi0UWf-}9R%Et@19`JXtP zvwlZ#U!ulLd3NIn`x@!<$Ygks82-qP_@TM7)cJ#EQr|u z00jK=79*cB>)sBsKGy4e~ ztYIhSdPA~v>HU@xuWnAqEmPsU_cqVSbi3u5ws(Gxvl7^{PNE#UNA@urM7I6F;l;#y zUOo=8@Smyr{1N8U>n=9Bu>>&$b{~3pT^$rQx_=rOQ59 zbo}Z}mq@d*aF*;BfzgCXML2Hu*~`NZXoW=nn4YhiE!1~-`|2;FN=`V zEp7{93pi~VJbZn#ZnrBU5clqntEKBAdAOeYFT}$A7zno1XCdTa%eIz}v);x`fPIW< z5%wJTV~m?8z;-#(+->np$lQa7Mgiy3%h*ZmI7y^N8f~geE$`#SV1)OOof{y=dbVzE zE}1oi`>}$~$XgoUvE{ivv3A*(NRrE2VYb_5b|;0I)-EH>eOCP#2|r``ID9&Xwuytn z;9e{&f(>T%Y}#3n!{Cp>`kBO=21(7dhIugUi{FoA>?dIHWhG$uBgMWO)Rt*w@Zj$n{0Uu0&f!30}L$W49La3hy3s5w*)!PL7he!w!YYMK(ub7`5~BH%NE8P2j`5C zVEplD*h}X|L$S+k_@~CPcV!eA$t*CQKrA8pc^~uOJcz~#gu;6v9x(hLcO8*(Hg^8w zUPb#Cg~%k9+_ue-%ajA;?WM-U^6SZ2`=Bw1@;m+$940m2lrkAlkRV5vjprxy3+D@R{aFz9NlRp{9t1q%8%r2*FVj|$=E|74& zL1sY#hiA(<5N9m1Hsh9S)L+sI81KmJA@GRQp|KZ!+ic=u*=^2G8E3NP?|yC*ojBZa zHXhC3C6n?v>_@*c$Lyqp=fT&P;SRwDvKNSJJV}s#!{R3`i=TkgEhJoqc_Gw}jf42v z{>c8^TeO$J50=bhHr2h&_S>VP`MY z9hvH(knp^=`;1Wvd_DFYx8!`>{9l&u&6KjsDRSX1-F!YSc$;$)Xo*uzik8 z6uGwvWIGu>OQq8-CTo${a29+gU^{=(mWeFA_Go`5X3_LEf6su};XcbA-?0b5K1$s& zgvn*@U5xo89J#j1j=wQtT)X%iX|h2+vLMTQm#Drn*4?$W)yXV2W4X&1AC`KS!PqzJ zC5I&V-2IT8$ZVN=GnRJf*?D${Wd_e;*+s!KcG$m!`!3mu`c359Z}=}i!TC2AC}$VA ztm?)-9ut}S8SS8-+p|1xLfjrt!*3_alJZ$N;g!K`&Jf9*`L}P*4<)Uzu4l++7v&}IAo!0YkAs$7v-vJrfXWi>ud5dF-pbA_=DkSy z_*#_j<*y92*ggHc-^5#U*u(IN$FsO4!af=74a7gmeoVU{nxgT5T3jC%>8uqT%=4IO zkm`LQFyPN%dwQQaW5&?rs~Yp+@4(B{HU;nM=#gww;>%}(TGbaXAsx0fcGKYU&9UdR z@A5TcB2AJ{oi{T9wsR$1kkTRBV%>sEAnbbhKR7zF?g7aD{7bTS&AYqfGHbG90pw!e zoFomEq~>|LUagIXm*nO6FTUhq5sX`o&m6b5 zr}SQl#RLBU%l`m~P7+XTJtQP%L(BGEuWo`6xGuk!mkzrrVtk6xd(vv;uSx36E}L|= z*=5OlVH4s+{etEpxqklU9QF_v&cqA{CzA5^O#T<(Ew6qV$x9YK+<0Z;U7M&|q#wq7 z4=lb}zaSa#{{W4U{{Yz*%*!|l_DCkLEIK=7hx~@SVn?%c_V?SUUetg+>ZZWCluieWPVi9}!1&&V4n?A_9 z3&ute2qxG>zA-BTNx!o^$o^eO5v>7&#AnNMwg)WcBiXQ=-rl)B&$Gf;^3fwhiDu@+ zawXWzyp-$@@&;VyUWQX^zYk2j<+gkqWe@B8CR(VUkeTD~YIP;c*)sFw+A#(Yx<%5_%c~U#()}g+fjKiP4nR}znBZ6h z8TN1s$H&{p&tKww_+~%T=ig9e=OL8&9>Z=K5tH_jgA}CP?wy}zOST#1>n?&I&)L!P zUQ68gU$#x_04ERu00II60s;a90RaI40000101+WEK~Z6GfsvuH5W&&# z;qf5<+5iXv0RRC%5Ojo~#w?||+;QLfV6NN#O1O#z zGby$bRRZycU+k(_{DkITuD1juzhf>y0YSa%5mNHqcjVLVQ42}ObHjhsS2!Tryx;W{ zTo`10Ao>^{z^kZzF~Oob%p*;a!Yp(ANlMT0^Zd|a8PD)EyhRycvQ<+sk%lFqAxnFS zOh6TgJj+XM;t74msk}y`Pu$wPL;^i~f-t#g;ybyHqN+%Y8zE)P+mvJCJPQY>P|*gZ z%}W<@?7kvj?OZ}uj@(KeO*r4qr9Yz8pSvaz0^6I>=M=}}3dYri>g7yo6gPL5oWBwK zk-XT);SDBoxVIIj)KMI^s(bnIETUnmTheaeb&8|e;+#U#N^pH^47K*??fupaGpy7? z{qR2OFez!q6t0pN(|pV}O7=~Al(~a=eZ_P>V|Oh~nbh-sWf&(Z5Sf~YrP&haq!ooh z1|?La>RQ^sfdC5#4RtR>Fx*L`60hb1y(HRJWv}P>RAynOBEpz7ID>FM68ymqGabOe z4s$RrS}muWoKHi{t0<9(T&i?=d%(C+)ucX`a06d(p!lh(GG7>s&{{T=+ za}LkgyMg`u4(qk>fcx_Z;W(b$pDXy4#pPLJ+Pd=wP(x^V_2Gd-$OBG}eadiH0#m_f zEgU(-Hld+#0fyxr?u5^ho%?)1ike(|YacLHNKFv!pIe-zBGhz2RH<(gOA>v8TNa?EkF9CA#Xm`u$H zke8QCMFiToh%pgtTDa4}nPy~cj?Di60$FgXzk#Spka5h%NNHmo5l~F3p+U}JZMkUh z4PTcBnPwdzCfk$BQaHwAE z8QENs8Hm~~{!GMUJz8(OrxjX$TClgEHd69my3JX8gBlQ(2;eJ@>m_7j;6YXo3+Kct zu(A(r5}iKdd3E;%${#Sp{l}ax7k7U#M%XIuIA2+T!z|M;+X0JWxl~e1^9xs&D<(

    K!|Ff(_{i$)YNz}*?rBUi(_g_+{nzL0tbm+8Fv}2qh;^UAC_azgjY7`a)>7IqZV$;+vCEAVP!An0v~ip8{Q$~E@NI5;q*5EUCJ_Y)eyzwH?-62Y|B z*#hG$xzaSAO?fGmmQsck#SR`HCzvU1f*!DscW^BzqqYA4O^*+WeGbHAn-5z%(|IXc zlB=@mT&2}GrnJI9!aPldVGOG(Kx7%JTkqmK;bW%`V>*QbtAd`3IKc?0&?544_!H)4 zY(+r#Y#J>Uo0RDV{y+S2xFvz(Pa0Fqd7&)X_b6-X#MQIBu_#T>Q<5^>~4z?Ng%aGa(;Pq5Azo>cC%P^kplsm&jdyquc@;7q6U=25tFO zu=xk%jmH6Q2lVCa>LJYPs#cnPKJFVxRe#Iqy7v^hQcp^;=k zH4HT^t98s$zcjLAa)zAs2C4CtfnqFm4<+JLh^c>$gcU9pmXzGEwu{`q1*79vvfqy4 zHE8Wd+h8V;&Hls8H(!kVM_JK$r=!dz7E0{U{N@XY39rA*zIKh(YOS104p^jgq(2l+ zRFF9*M`*OI@B; zlvzVvMkx<+dx{&0<1u%4`HEX#<%m`#-Y%5$>Y?RE7K zhP_wt9t}!78jAps!Dw`R2l~wUZF+Ng_YjUO?H|)JgMoZq#45I3*jpC?qkb=$noxk7 zsDcDd9+Nlvl>mQSIpe=%xUi6!;T{!^=z!E88G+OH^!SI40)?7J!_%L*82}|55BMP) zz*>y@Khxv8E;W~lLT+hetX>>Kj1mJ@uZ0Hv?rpF|xZ#Y@pQ=y~NNR|X( z6c^<$>~b|wf;602GH=0Sk;Msz;Q-~`hYEkiOU>bNaDtkFn&Q4HA7dK5(NFTolyov~9b)}a380XaCC z!xqDaTc{%Fl}l9~v5hzq+|pRhrTVl$q#qK-0r3dBiL6o0N^;aqYYQ+fov4z7fs0lR zA_o+%W@ldEp}#QW4MEG?PJ8}e&>U9ZrSJGknj;|n0I4|-?a0xDK zDd=3NuugXf@>}r2Y_gJ>SCEG3{oFC4<;?6m?=1G*=Uv00O?qL zfoGG;8nhZVmX8bYD`d_d902{mDT0Ki)W#b1b@oeHDL#DtO1{zoBbYFomn<_b(;grg zl{Ilgsp9-WHh)v1b}=sEb(mvOOr=0piBb2NM>4%ZoJt7u02qXPp;JP37?Z-Wczlw8 zTMS$}9V?kr3QOV(LgLnbV6V3cU1j(mM8d1joZ_Q1VvTds4(cum^NCdisJo@9^D7Ke z`dG+HML8TWHz+NvC=r`PrR9VIkXPIxt!8Wr{y_PHHV-~RJL2~eq-d#Tf%Wu5Asxm9 zL42pk!wNb@wIS<&QpfEM3mC6Y;$FowN^XVtw18VFoUm)*PqI~Zih#JP5UkRB3#)W&D-jO>Mx2)JIDN7 z%jM|RnFqp+aN7yURWzqd=L^{P2J(MZh50gk%*4P@$Y);Rv{72_3|nuXA5sBQ==N z!WWAQ9Ou#p*T|)wM+h=QoZHa zc&h&ZVY`Bzj~j>w1y_rNA)~!*`1x zxMGRaZi`-)_=7-0ti`U8W;jb&!^?{c;!&_HT|GSrK8cf}^t1K^%TKnfpudHSH;tZD zar0D0rLlA-za>N_#f5phsKQbmCP!<)5h)KJ|LhfWT zjn!I{$!J(@7%q+GB?VqQ0guYtUztM0$@__QinY#CAg=>n6aN4pHpxx;BOUAm<%c#f z*f;{xZw(mk>;CZ+X3I7TA&aZt@7%=?LDW)l1IoF)cSA4wBbpGQk8!X;xO%pzT%Pt*{3X9&N8 zeZslrPA|#wHg{2@$zO*505vb1i(dMU4AEu0z>2V@eCk!80fwmJ`1~951SRkukG%NF zHt|D>C=b~RIgKsS$@~051p*Ph6KC#GgLGZ@F&g7C)f6HP2IE>w85u_psH3xg#O>5} zECB-9P==*uEkTkV*@|>O5bc6vA|ZO5B0^axqmhn&ka($(OccPl;^m%9SOQ$#W8fFe zxY{c4z5f7ER5rHzTm2CiYjbNTRJd!Q4Aj!ccyaR1nGE2tc!%gs>pwVLU@iN`Yx}4O~Uerk=Zi z=>SnupNOv2<`O}lsm9=f_ZbY!J(9IuNA!d76+v7?$`W*J+yrceo})8sD{_@x30hSx zY^R62e8O|dFWZRc*vc6#+%Xvvmi@VeCM?Qtf;6<5~tEtV@ST5B&sKp&x z;ueG~_YhT(s%gJiub8B9_|Rcjk@vk!KTmOt2y&W%-iYYf5#&SY@P7!WXi%>i@McVj zB!`0Q2f3 zqM%q7Zp2>|^(uWH4>E*00oQOmwIgU5eue-5fmG;Q8}PqO6oTDq#~J;6_?d+4l+lr| zN7hl05rO5)@X=#0Crvd%KD_LUb|A7GN-9UBtcu8xE%g zLfkedP~ix?-eUp8X?`IhbqfCA%1ku{QF*AjiJUOdTR*sH3kQ5}df636Ze?G&Z64q9 zF3aL7cGd}!=W#7Rqfoq4oa&VQMzY5zI43Elj{{Igs{`HypdLW;Qh*Ag^Nqo=5;KAL z{{ZaKgo?z{W6699V-f9#&e*p63XTz25DQC<<)Yyg2R*n21yQAadjf4t4MsBNjZQ%n zDPu}?2Lb?9^sz>kn+Z4M8m|7pQ=E+?QHB9UcV=~r#aCnoB)1Fzt*OPts@A684-g=+ zXlDZX=7_BDg3fs%3s+Rq#sS->7OA-A(5?A;57a2a;Ts?P#HEEmzfG^d*^FKAo=^JE zxrM?Kaa2n@KitObRxi>BQv%qBl7ajq+;6y47XqH9fI;DwBA9EWxOYqnq@lE61mk#& z%Jbq~TR#%QmK^-e{{V@1FM$43hy&rwzARCMHf|j(50&{wRIn@NRjRATcqPc()QC%E zj6qv3kk7bnFe1J|{{XNq&JO$#POtnBL|{J)yZlRTxr1gp;OtS8{{WDlAx2q^-!K*Y zi`O{4{=ZH@myFY!Kkq$iUZY@G8yW+p^*2xrA;roodSwk*7olu82Ix#?lTjDdtKIYd zKl=eQQwD~!w-~ERg(j){Of96&U$;{|AGZ?r!=bb}lp~mFOxbYf9!YuW{y~sCNgbm9{VgmgXkf7GqUww&t4r7x{@&-iB2Jgt1QHLRwrW#8p}w zwt^#?FQ;JB{zqTSPs#m8Laj~lMMIY*hibswDPq{;JU~j8T@S?ZW0iP|C}n0b@53G$ zc?CsWlYXuVH7G6x;kcri zz4>G5_+hkK3d4OwB(grySi-NNhv(`sBr5T0zCSVmn^ZAxUlHR^mOSKpfh!4y2i!4T zyNaP`A#5-LQsHRi5Dl2iXNrc&?1>H3yg?8@(hy|>)W!%Z#wDx7k4ZNM$19n5DG$pM%77Ui6dvG7Ku-SvvahN=wpR9_{w7B>ju;BR#6N+W zVC4IQPy<0k%le6+Ko3@jx6I9-C>09|yUlRpdX|1+U;t*bPvN)-KeSk$$!Z23qO*1J z2SH63#6DIt0vIY@n0#tea7vmT{af(~A!6{BtE&e)FhB#9WTaR!6cO^k{E8*dlyOkn zEe8p#x-l5Lg`u{w;|cMZTisBrC7;Gdj9}iBEFj$t#q+a|omIf`bLt7FFpw-Qt|l{9@e#!4RbTMc#gdpYd5uL?8sl*1Y@ON1q89-JXy9sG zB87xmaD=QgYhQv17)IBSYtXT+vu!nq7oxr1nOO(Rzil^Gj{&~6&SrobSCpm#!Qf3M%ewD zVu3!P5e@vy!#<-?xb$sfGbIToz^CxaIYfAdEEhwTyVTiO1zN6d_qI6|s-bKKuC_Pa z5zU5;G2$@bNkx~>e&s;?v%?ioqna6gH|!!2rjuap=M@D-RJGD)<8qajw}?ORSS|6u z_^0V(o+w9F$zi`3iIe{6gvyKD=Bn;ECS6oIgN|bwG=?C+MToKw;|P&|*c72YBDY*c zv@$e6kwF1Lxt=0WR40wW1jAA2AW=CmZY@skB9^All5Mae>ll97b57coleyKDGQKx5lKX^5U==@f%l0oUr;+Q+6M>F3e;H`~ zW3(!p)DNoE#CPUipORx6`kR@U37Ml)V9XRvvo9BkNU~fkj{Qn_eAICSzM=|cc#l%2 zLM9t(0pPRqQH{2fM;00UMV-pG5TN5R2CiX=QK(h>^o6UI7!d5^PlH}y*GATul zZp_nKrMNrdC}EEKg_)Cz)C{tQWvb=JMpmH)^fa~|#$>9fS!F|TR83M462_`92Lf1~ zF{a98CQALM%yJ;Vmw9fVDW)K}B`U=nS012S0R-m&e=v{=kMbj1ECvV;6#^h5PD73- z42L32JB4IbG2+DDWqU0Z%odr)ai|sb46!S8f!5*Mc#hbNlrA5nwxJbkZxYxR=?uUe zhIJp782YC|WHOh12H>Vm5cXR9Prk$yu3CDLj*`g076=K#qEy0S8nd_n2f0H5E6No2FFPtQ&D0<) zR&F-YRcENmQiYK$8JS9jfwaIREAWcteMck{aBwm518_uFED z;L5po8dGuWIt;I)%)c7$JwiU_C@gY+r;=3%CE_*hCv1)3>=+I-rg;a#vYr4a&oZz_ z2N22|m*s(vipJ%`<%x#Q)JNtG9Y<7vvcmm9z~q>RCvwrAH2|@#KoOzXLIS{tM*<82 z?ylu&68)Dx4zPJ_pnwR6EyB*`ft#dAf@M$QS*G);B>@PzK$~IBj1T*S4CNc$218C3 zs6V@k14LR1N{q^Je9DD3TH3(EbtybSmW;7fKNCbTD?pmW`joH-#Bgtz1>935+ql(o zuxh!CJe8QS&%~kYa?1Uq{m3HUo74(IIhIG_z3oW%=Cyhi~LD-1P;t~ds0A$1l*itKYNx4$rnsZdPz zv0mD*_A8Zq!WM^?D?tmmi*CD)*YlMuUokvaU`5TVnBLstQ{ypqIRxUfeZ&MIv%0im zxF4h{Ivfzv40M)Ql@yNZ@?_-JU`^>kK!}>^GE@|v)yImJ+E7%@ad28JqO%2E&g7tG z?g57qnBo&R8soMQw=Kb&S1V;tP)lFtIJTu>fM5p{Y#i2?yCqHP9HSDYVJ`59sK-cx zHnQe8gwl`2xAiJtMVZqbaI+4aTJZDeoGcf9jE~zGwFqmCmHz;72Z;wBx&HvXM)H6? z*$#&?_-!GeDiu(30>sa#2nwm5wQq4s@RW+=Ts%<}h1S>`;2?pk<&EkxgOf0+4Pi@? z!mD+}yu)lUd7F0(S(fTn-W->xgAz*;vmHLIPe6T$h_0QT+`J5?v*rnM+w}-gHLXMB zt)z&A+70+FxYQMac`nH;c|b-c#Kb;PXl(&*rh`yXacM;cGgp}T%czBJVeUv?+n43U z=mA&p6cvI|d;#KdfKHzwU$E*G`?{5D1wXj*5w*VUg6-8_MT|mF6A=Bz3d&YjGiZs8 z#1C+_Oon@D%r&z@bTwbpJd)lI57eRiN#JAf!Ylxw>C~)j!G6!gW=9TwWoj~$#3eGU z8iMygaj8xM;eo4hr8waQF30GHD?gHsh8)?vG1DV(DNf*9jN-?L__>z}yN#eFkC-C{ z1w(NV<3^HV2~SfiDw?g>K~-xzJGi%!$E-$1l`o2o$P4gB8&-~Gwhe;#k4Uu~ArFgs z80!LmM$gSYAUsi*^KgRUUCJvkRcJVi3j!mXWhSxi95}|BiVTOQP&Thwc-+hzt2p;k z$zPx;K4MkPi)#gMr8t-;JH$Xz5SAsy4NKIxw-(j$1EJmR8KJ|Yj7!M1{GnKEsb&Rf z>kr}wEH7kCI5J-Y1{71DQk@Z&AFV)9YET9iRhyRa4XBHLql|2o9pv1Lq1GZpZMC689WgKW`II7Td2@aaBGC#P8H?Dlb$T*|H z6F`?cv_u_Ce-h)hJ$~QrL*NNGo>+ zIjB9r)Wkkgzqy>07xf*|U-u#w$|ZcX{>aXq3(r%>tT;ksVL;o%xx@q$)JsJw5{n#7 z&q5~Rz7n50x^ZAZ6{^4@LF-X|VzMGg?h^iqP z1eLx6mR1S(=b_wrAP9J*;U^I0rr6DBM_B~%)SjutT8@Bak?1F z`b2xl{lX3`m16usyfPC0%S&6N1x+;wxH5JjFz`X7qENBOyJdyb3LU;6A&qMhr_?mQ zJAsj{T7|`3lY<{vl?O$4#I^C0_X8I;DX-7{s2Mj;c+a%^DdqyL9ZUJHFNmaLCRHhy zou5+V0Aq`R+g2XP0<`PIR0Sn!w&EH6qPoAiX4!jnDJ(z-gbifFl0kCHgi_a&h=P%9 zpboxfO@S7&lj8C707x7FG(?kANK2$$7UMFIhTaxqV{{Y%8%xbt75TU4O{ioH+qW2REk@|_vw*8v?TtdG`;VQqlPf#ou&SR5y zYE=u~<$G#xLYh03yIs>Ai7@f`auS$%6Ozd zEaOF5;-#_G#qgiiP0mzX({kZk)aRVT=7+0G2~wEO`-KlZW*x3XHOII}u4~*vRTnW8 zxsoxA_<@;()N`zaU_^gV5-1e{H!Fq>bjp!MY13EBw-G@QCEmi z2kzcx@g4bp@&!haZa5{?d{jznVH3WVm~X=HFoPt^dxoy>IVFkQ6$i2IWaPBoR@jfA zBE)Dn^Qk~bBa2}@^8;uF4cQL@;xbVXMx|+lfxC-LQ)NT4cJgDGs^tV6)12`y7y-3o zYpg7GRGI)7N{>ul6UBx3h=hW$XN|F3ocWD`VVh^UiNwAJIlKhEUDPtY!i`Z;*q|5v z{7%WW4S&e}##&nXQWFBhMo`MFFlnml{J`DAZTh@_WI_rc?TV43ntB+)%<~C+p)Rh= zZwU7{1M-Da1cbN{p0t!7+GMyVEP4L`i8@hh?=UruFUU(6Q|!gTAbK)mA5 zBr+P!j41;a`$Te#cUk2mpUxF*Z(A^(U(_30JKqXsSxC4kGcN!=uJ|3w%Y+@yQ=jFGT+-7-nZysX@ z1y`9tEsk?=#cC9o+i?n&eK*a1AS{$Uj_4~`2?I|OI?aD^$z1Uih0L#W z?%?6~uc-GEx81K~s!3`Vbp;6axa&(QnT}-l7%2{A7{ym=- z=!I$tvJg%N`;>D`SwUiZZk`Cv)@t^*6l(#M^%BUcf2na&s?TtboJt!lIObLhXP*!T z+vsvXaBPjVK7Yho@aAY&WD&4!i}WClDN&W`Q@mVf%*^%L;Z3_l2)jXCej-)PAz4OH zwN`_0@d9@Wc8i;XM~G)6DMN^Phm1lZ`06$VYjmX_+`LMXJ>15;pKv%ha}~WfV6~+} zof+KW=%?599lYQMlHgn=rSpVUPaVojaa+8_L_jd1v733E&N@6be=~!Oo%uV5j#wrJ zzlG>Io@K=}kZM1LH8}VP2GGVxmW_7<0YF53$}LeY!i7RB#l!Z}H!D|_`URa;dW7J3 z6b};ALAo!TmdXlP;>X-X7bgDzsDXF_e2f*Dr39GD4kZRpJVI$}Ps{Z(p7&X$ByVl+ zsF`#oP%D{8wJC^IjB-pMO89{FWz9~aF!|t^iGYyiTQi|aAa)4^im(&uifN^^# zV0}f8_Y!FzGl(R#5eY&nE46GkUO8r0EWP)bH||z8(yrw~F6&;PEi$*@V1rXa{pJ=T z7y?vU^}~mSmuFf83_lP#XAsMT7pGK$!KvF@_4<|&nj`-JlK_CM0#+C|5aIC}?1BME zl(OL1(Wr)ixTDbS3uM9H<}+drTM>Z}v=NvMYH^g(Uk8EaBP&1|+_Q+k(taV-77Gf# z12N25emInxJ4+mN3z<+bKMp^*$atyIuiZlFwDdTBnNW&An#@ZHekBbd=&DBVj&AZ2 zQ0j}Y)IUVPL@Q<5Jkqk)O2ivN>^pgc*D^n-)z{2Rro2T>#6T5b8q3UTdLShVNq*40 z1-_k{agthG{j&^+FX4CjhepeUN-B%Fdr&E1oQ$QmF9SjtC>b-sc$c!fePV%3C8kK3 z8kBBmz}moO0M{FEtwo4P%24l}BV@{?HkrA!8mx5Moz~N1U?ZkAcjymn^KNUZL@EKvjB; z;pO-RgU~EsDftxFVjepG02T%-7tWPYNO`M#tbRNGn9IYXoJSlCQD!%&N`zpoVS~sU zj6A^+<)eAJmO}!sP?rAyxE{$s*=EPbaNfNt5NxO7;-X{`y3&1SSV*)ZPnK#q!lSax z_Znb75K|!53W`u30BI|(9oP6^-)3CQxQvMQi$lax?Vyj2 z`j}Uoz+=q5hf=I`{{T3SMX_3^0i`JOMaK$2#uOLQ+Qc=M>VO6GH2D~PHiP#q$w6KM zzfg?BoADHE24`3w`v`F>-w|@%pUK2a$~O5|65S18&{kjtxN7hDPg1A7z}{ti7I{}y zqu3)-+IDXMY0Om2VZ*i(9kb;?$Q~5%)YI};Yb@MoxwllDN zLBo~IIAoyy`iR1LJVk_XeL!MrI69XAc({{X51*|;5K%oI4b`isJ=FbuYXT60sTgBFAVDKQ67#d&HR zVPNYgk|-jQA>}MEc1lG%fJ#uzxHDux9l{xE8=?c?6&%6>YTD>6f)VQ-kp;?fU1P*u zBQ%3rkidv5!7nwuqcq_7m6?G%PU1Tm3&xU%LV@f;JcN40u`;f2EeGyevcViXPt8w00%Ps}E&F3pJxr*-h>QBF)F*A;}@%FmTgtxaJ1Rd`xk2FUWqO z4KLb-!V?t4PcR$j%)JLu&^eAQVlatT*Asjv03ISB1&Dz9M zmA(q!(m))NqOdEUQ(Qr z^+GQc@W`-f1r_PW~= z-n?+ZB})t_UCq6VYue8{ z%^|?^qc#v;7$wce0#)##osn>MwEW^YyUpeE*M}dt467mX^gL6RX9o~@;#gv68{_yQ;t)Vd;6NqR z6d1RUEJ_+ix|Z>co@10U5Y<~o$k{{#wQ~MtwryY@`-&zeAGknz(YgXt4JFmf0^vdl zlU0-@j~RgWfM8%nrrMN%)DWvd1%@b9C>rRyVM;d+_o+0xq~@}37R-z-$rnp<;fgtg ziPWr;{^;%eFu*q)wSH8O@YWeCSCpX~(9V}&=;F^Z;5S8k7VatPx!%FF{1bX8_0CCV zqgA$M4FI*|+w#DbRa$qb-Uh011k`MSQlN!W`zotJVQv?1S6v6snrQlmF;Fc?D{Sv- z97BdJT#*MfFkdQ2LRv6-2%-QB8m%#&J+5$y1 zmyxQM^esXG4w+f1^O2?8VZ2ERlx_7VjCk~s;#WUg(?u6rZg*&Osv_UqaK2~T5C|v zo){H;90s_!W{AojLxLk5s8fC)h9IkjL-P8REhDD%^IDdWH)ZYUp9_$IA-wa|ojfKU z80UH_W~8%1+U5ymOTrJt#@Tj?m$M6l$9XpSjcl~eVb<4&eL)S38{;~dEhu8e%@Grk zLF71pkirG0AZfT-6q}Bokl?rpQHW^ES97)1@s_HP>Rm#R`5U^{{Zcn0&*+Wz($c2yCCEKh4m=R5;l%L zANvCh5PRsic*n#(kReOqb*z5kK#QuXPZVU|P=?BY0Kgg#5n!lzl?I8+nM~mJO}TzA zhyzTR4;+a{0;SBhP2C8cp9hv1U&V2QWKM*FTNaw=Y2#TL|!HxLOGzFZ%hxr}|b@+^3=Uui2>@6Q}fh1V9K zt%5j!)7vQe%jbxO!iA%i^9;3&imw9#fUF8ZMJm~RzcRrdLqb$9*2~4Ai0L{z0mjT7O*vf04O`8!Ssr8c_3%qy)tQ4c= zfrY#1p_^`2qAS^HN9bu13X=&DI z1YD#T9vrK^MWl$DD03Vc;>Kc|9ty^DF3Og@g%S9PBpsY3c>0KKI6sWUZe_}0zxc0gm&)rC^8Td0O8uF5x@mTOZ8mZ3WaR?3~&NfEx(dWIABS8~Hj zr`^O9A-}Q(QDf%e#S5B0xt-$Ff3TYe1VKUY9;QHiBf~1n%XVGG7czpxcZq1OtUsUP z&RkA*N5q`9zZJe14V6L@S+o_JqptJJ1SEiy{KIS;$$ZhKa5vOSDldH~ilMlox|s1OX2 z)}$P#ELCc%y^&UBZ^Xtb1r$c|KyqWt2-O#-l+Bz<5nwrt3e)6`cn(FSqxFr+qaYVbC3K|Wk)5N2MnQ8A$*Eu2#o~`v0uf&f(4)h z0Y2inDuH!{bzdYXs1=E;a}nUsd=NXca$3v!U_g>BsBx|$TPQ92jErY(ViVXJnT}{Fk@GyD3 z72LTZ% z2qu8wSu3*G+w*1ua&hCJ18_9Lt08F@?3bwY8TPHeF~5n>T0SF_n$PEZ&@e zT>+M6jV(dH!*=G*;RznAaCeo^TB;vl33vm_q206ED~g_@dq8iqkSewY214x?!CZ;{vBuc0jKO0}1|_Qh0_`wvet*oqWQ6AhJzS*yXmpMY`3IZz|O-9;M7!xwo=u&ID?( zfj4W*mNK41C7Y{911f@_Hy*FJt2iMXWgbk*d`>!jiGDeY z1U^;?PQMCerGrW>0M&7$7=zK$SQ71Wakzks45eZ^VOWZ%$3`|x6Ocp8rynsY(jekL zH`+FvT(2b{V;VtdOdKm#w6Dy#(NjVQSV!EXkAb^j_>?l&q;f7Lkg}bpkc!b=SdxH( z1wFSgQ`}1>?YNtRK&&DWYgofpgGH^#%h*tS(w#y{9bw8DDB`$8%t&}KMS`g`(Ay~^ zMyYz9kE*PbBwvK)T@Y`(%|KL5w3^9_SQ|BwD(Z?U$R(HY0E?`p*r)L|QU#S9IkuI+ znG0k=wF8jo;wwJg(A&IQC@aeTVOf`{YX<|uFNc2R%9%h_J9~`|hz}#>_b74Ix*%F^ zf>Bs|mX#?0T5uIeO2uMX5YTOnx&xon{{UtLr`(MZ7>t_CF#<4QZvzD6s`v6sovs{CFLvvW13QOKP0E)t0D&LHM-tIWVx zu&u=#PX`aWNZOnu8<-J-}NWK}NWZ+aF1D zf|l5^ML1KKaj`sUyaEk5R5v{&R*>sF52wr^mH?~3)r>UE+6>72*6cV3;Ix$(#(K2} zXE`a->K)Yzm)1Kgs_r0k7j?c6DdaDA1tEmSggjb@h*HO^cU7U7JFKd=t-TeMaa+j0 z^}$!#quC3)2lo(s#TmDE2VV? zv=&)aR#8pzbIC49_!Rx$(!oW?Rbu+5FsST2X!1vaW>9eXAsfLq*D=^x+y?udy>Zk5 z9Ue;z2hKf10WE7=OYdF4WGsp(yfiF!bIhz_2CVfY&c@t-o5!Hd0e{j^8 z7kakkP|-CJM$9e+-P-~YgB2D>lxurTN*N0Ecv$a)#172X$BgUdVxG%}_+fB?P0frA zknbN+0}GO?Xam|j&=XjfFI1$GQZx~CCqmt^pDGM~z9+3fGB(QXuingG$0;f6HaG> zWvzw|r_DYyD(KS&sP6Xd4ZBAdME_NBc3ej4rQ5re%ThCWVu?tknN<)i8?JhSM?JnF zLe4NN&uGg30JJMI&F(9Yf~tdVby1uy)`pL(9Q&zgi7}9?m1y8@22rR2HlX_3QwbJw z8YHw<5ZNjHRPAoRWK4-&5c1qrQ%?W?WIdW2zXyWQssyCoxdHC~N!*qBL7 z>0H7t6R1?Gmkd6}z?*+V-wEzF-hm+4bO?$%VcqP`FMk3dDAX^Qib7(PArnvT92KxI z{0^Ab_fny9sZ(S=$gy=YZ`rVk?LjzvN^O7vL@ezA_1qCl0gOoRH$6aP$Tg3^6^W(J z+5yLF4@oRK({vO+I6NdD<1o@=JSF}j=M?Qk{@^sJ(kS%@R8RKtfBfR!6OzK^H&)M6d&VLK1N>!Ck>soIw>eD7zwLY1{%vCHP7@Bc`RL z^Z9}bsbt(CX@gE-cFzs7ey<+aVEO5v{dI1uE=t%WE9z2b0Ww%#g6u9hy@j z)h#q3tt2!8?OWs5lPJ7-79{m@KM+O}V}a(;XBH zmSQ}%4iwxn>|ii28EUK2Jxa^+B*atbN2Km0-sYh5e>oKMjWJ@Qn7L^`u>=ZJn)W@S z7ecE)WL8+Q1<9pxyoCh3$q%Ng46T(minfeVyg{t<3lZ)IlFxsEDTfsgHHd^47bF=+ z;W@?yXPlMo!%&yvt#i6i^(ts9R%0vm_*f)t=aS8r?=h`XZ4u$Uui%W82wNDz_4yI2 z4a3eVKTu(?1;U(MzsaE8>@{SqUSI;ks;z3+&C&|BT^LId_U5s4f3C=oVp`IgT?$R% z2yPSrs)%B{#XttmrgC6Hxq&c~m~05HyNJsF0FaJx099exDMbLayTvTXHIu}C1h2Mi zqUfU@h_}|#f*xKG*@no6!P%m~a<#aObz&;0aNeG!vf12Mn@b%8u8&7l(cm+WC&Dvi z9I0$O3lDj@LL?6dhfWJ3WGk5n;NLbc4~AJ4yr5#=z_jbRUjPoRsci*I7BPT|BKg(v z$ts;QJyIaK&015^h{s4lfE$DkHtr|FzC2-KIs#eDxNa^>m(abu_=>304#Qi`i};ij zg#a2UF7j?r&_L=62QLR`TB0dLw}%%J^;yEg}>2h;)`mI7XwXdTkP! z{yoLWm*!n!;lw+zZlO}z!=3|bZnI0Oa#=uh9Wi7urHnwQ6i~C3Z-^|c0O8bgZFN^* z7wS{$g5-_S#f&O2n2Ja&2EAX z6vFYC=JvL-@s?wnrue1Jf8?%KA-`k4A2F6ZJ&s0G((D>CMGCg&WB5{33cj@hypc)V ztQC_E8HiLmN@bF1$jnkewDtgrUnA^|lybrfq+6_juhkOPlF$of`P{cvU^WJh79MUl z2e(y~`Qrw?ALgU~03Zzl6m_TY{w7Bn73veT*oH!oKklFrx6ePXBtT{hrhpy!l?lWe zC3}bz&Tz_KmEb!96N~;Yc&MXBF6Zrn9oR83E%9ASJJJJf zpsa0%#L)2vWZkOLhh{$gp;e#@cfB4WxwD`h8v?G`mnJ8G^+)7GFw%V8;X8N^XB2Bt zR+%efd#8v{lQSl~r5of?uq_fP=eC6(e32lnJ&cY4=2ieSKGX8@L#@*lZDtkP5RogR4H zK#HfNC!B1Is^aV}+0&EK3C1N6%35Mtd`g3qhC-;Q#tNh7;vdz(1Pvt+fR;1s^8>*= zh0!aOd5c2Y=x;h&^C7-nqbYfmpWA;U0r0M1s zD9}C+{=%s%w5CVo`$GEL_2L7j#4zwh*5N=PCNOV*LY09a)sV8&5gJY|HDaY$M@&>X z62i)^X0kEH{K~S%3u4&85t`|zCrd1BTl7H>AyKEO1r{V1GPPuNv>Rbc4|bC4C5#aP z=7aJ?hjZo*5v(+J1T&)Zs@CKMZJC9JDWZc<~r$`}h}Wv&x-BkiMrx6!~BX8|;9Yd5ip~ zz#(mtEi~M;z#J8EX|A@n1odlu0>TgOhN8j8cpxblT|$R=m_6i`rs=~SyFky5F^K~K zs;HHFK)sbts*3T{N0g#=q5eZK8!h!J%78>SdI$xuDcU#&J)FKEDgk{(W+%9t+!qX? z+@dJkh_13biY185r0OQpm2m|3r;SRB95VdE$#{)qJWRlrc$rhYMm$`8GhpkD4`t&0 z;yQWYyNg;prw#aGm_TEMQ0))HDhWQocgf@iIt77jayv2c0@T72VO`}np^A+y+#qkS z4|0i(@T3T?S|4+Mg9BK7pAyXSnp0QZe~}C<0)`uTsug;rHbOUr&{IE~6s-W3Hwh>d z5M^HPKF<>%`z1&wn+XhvV-;{K94{rQTqVk#UuaWURwb8QML?8+O=pPOG7T2+pM;}7 zwvw4E0WGU|5iAWF3tdM94UMR6URBE#9>lP&Wwd{kID)0Abh7Ul6c984s89fYp$-=b zWG-`79TM0?g08z%a?+4K^G82|54w(~uhiOQ#qE{z;{!j03{?GN=3WAeH|U9fDhXW! zgB1bqP|TL}@-NTnGC4+N)qfN9z_`u+Be*EpFVO>*xBMu!$7HZg_=&I77OB98dEouU z#qK1`8aDzcZG*h46PcoF4{0l!h(U`$nMc$t$4%6?ma4^8qZfwtiik8MuvSpr!{HE0 zKLud6p3S|*)TD(1uf{?6mt>S(CEMi&8KV~pI2zc~Od?XWgKeFi>J_Yo;I*&He8qlP zim={S|-xxd7B{N&S8oNgg+h~>Py zgMIUyLo>`sUVOnzkC>TRmrCkfgfqmWT)=*dXUyvdczA%+Y;DG+c`3PXhN{yG%jTJt zX|;RiVqoM;cPzQsJ|Y4IZPxeiM6M>r1&xPjE6hh|l9dK01$_FHvD%1bE7mOqxT_{6 zJr51Ad%W0^k)FDRtLakyN#Zt8=}xE?c0nPecBO%(e6GeB41G{=T2R<2i@i84fwVx$ zpEW)GlPK2vGz9R3cwm)f-V5#%@IaBwxYS?K88R616kE=tQJFvhXz?jwJj1PSPz17+ zMrUGSd(>7b<_Vz{6}yUxsQuWJE=}VjRt{OXO94(xbIDu~?^9$7;P$BGCisCC0YCtt zuLeFNKwtv=5G~kO7v>3|wOE#~z|~YB)wRZK=3w05U9JFaIIhaXa7}qHS$d$^q^9mEPqb#J zJ(fA4PB&v=uP9bMFQF34i{p|xl@ArPeuFQz5*itlTifu1lEfMcFenLmE|B5rtOhsv zlKFh%jz&x+Q{azMzdV>R*zh2F6FG@s-zi!7iccsm+{89orw>qv#9pHCl?5D71)2d9 zPQQaVUv7nq!gO#KfFd-Yl}L8BgU}Juxj-4vExHDP00ILBZMxDbLg^3yu zgh-DVeOadJIBn&OD5rXud~@(aVS@lA0fSBJ!5pKHkp{k;`?xbH0T84Yb)7=V6hOyT zR1X9VnRFl<%@^o}yCb9o0a+1Wb#Is{ORBWwJv~L2Ikr(X#npOPPDK<67{}rx8R)Cj zb))057F$k0sf4GFZd*2~XBg`E3x#AMS5NLb#plW@%y+;I6GUy!5(Yv6fB+x^AIJaM DKbw08 literal 0 HcmV?d00001 diff --git a/test/__fixtures__/transversioned-site/static/img/slash-introducing.png b/test/__fixtures__/transversioned-site/static/img/slash-introducing.png new file mode 100644 index 0000000000000000000000000000000000000000..83945788689839aa89925a581f35d7abe4b546f5 GIT binary patch literal 15983 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 b_wbd&t}l-+I5&WU Remarkable로 실시간 편집을 경험하십시오! + +깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다. + +*** + +# h1 제목 +## h2 제목 +### h3 제목 +#### h4 헤딩 +##### h5 제목 +###### h6 제목 + + +## 수평 규칙 + +___ + +*** + +*** + + +## 활자체 대체 + +입력기 옵션을 사용하면 결과를 볼 수 있습니다. + +(p) (P) + - (r) (t) + +테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! .... + +!!!!!! ???? ,, + +놀라운 - 굉장한 + +"Smartypants, 큰 따옴표" + +'Smartypants, 작은 따옴표' + + +## 강조 + +** 이것은 굵은 글씨입니다 ** + +__ 이것은 굵은 글씨입니다 __ + +* 이탤릭체 텍스트 * + +_ 이탤릭체 텍스트 _ + +~~ 삭제 된 텍스트 ~~ + +위 첨자 : 19 ^ th ^ + +아래 첨자 : H ~ 2 ~ O + +++ 삽입 된 텍스트 ++ + +== 표시된 텍스트 == \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md new file mode 100644 index 0000000000..7d057cf795 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.0-baz +title: baz +--- + +## 이미지 + +링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다. + +! [Alt text] [id] + +나중에 URL 위치를 정의하는 문서에서 참조로 : + +[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## 링크 + +[링크 텍스트] (http://dev.nodeca.com) + +[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!") + +자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정) + + + +## 각주 + +각주 1 링크 [^ 첫 번째]. + +각주 2 링크 [^ 초]. + +인라인 각주 ^ [인라인 각주의 텍스트] 정의. + +중복 된 각주 참조 [^ 초]. + +[^ first] : 각주 **는 마크 업을 가질 수 있습니다 ** + +    및 여러 단락. + +[^ 초] : 각주 텍스트. + + +## 정의 목록 + +1 학기 + +정의 1 +게으른 연속. + +* 인라인 마크 업과 함께 2 학기 * + +: 정의 2 + +        {일부 코드, 정의 2의 일부} + +    정의의 세 번째 단락 2. + +_ 컴팩트 스타일 : _ + +1 학기 +  ~ 정의 1 + +2 학기 +  ~ 정의 2a +  ~ 정의 2b + + +## 약어 + +이것은 HTML 약어입니다. + +그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다. + +* [HTML] : 하이퍼 텍스트 마크 업 언어 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md new file mode 100644 index 0000000000..5075f44119 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.0-hello +title: Hello, World ! +--- + +안녕하세요, 여기 엔 틸리에 :) + +## Blockquotes + +> Blockquotes는 또한 중첩 될 수 있습니다 ... +>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ... +>>> ... 또는 화살표 사이에 공백이 있어야합니다. + + +## 목록 + +정렬되지 않은 + ++`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다. ++ 하위 목록은 2 칸을 들여서 만들어집니다 : +   - 마커 문자 변경으로 새로운 목록 시작 : +     * AC tristique libero volutpat at +     + Preisium nisl aliquet에 대한 + 시설 +     - Nulla volutpat aliquam velit ++ 매우 쉽습니다! + +주문 됨 + +1. Lorem ipsum dolor sit amet +2. 컨소시엄 adipiscing 엘리트 +3. massa에서의 정수 lorem + + +1. 일련 번호를 사용할 수 있습니다 ... +1. ... 또는 모든 숫자를 '1'로 유지하십시오. + +오프셋을 사용하여 번호 매기기 시작 : + +57. foo +1. 막대기 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md new file mode 100644 index 0000000000..1e9fefaf12 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: version-1.0.1-bar +title: Bar +--- + +# Remarkable + +> Remarkable로 실시간 편집을 경험하십시오! + +깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다. + +*** + +# h1 제목 +## h2 제목 +### h3 제목 +#### h4 헤딩 +##### h5 제목 +###### h6 제목 + + +## 수평 규칙 + +___ + +*** + +*** + + +## 활자체 대체 + +입력기 옵션을 사용하면 결과를 볼 수 있습니다. + +(p) (P) + - (r) (t) + +테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! .... + +!!!!!! ???? ,, + +놀라운 - 굉장한 + +"Smartypants, 큰 따옴표" + +'Smartypants, 작은 따옴표' + + +## 강조 + +** 이것은 굵은 글씨입니다 ** + +__ 이것은 굵은 글씨입니다 __ + +* 이탤릭체 텍스트 * + +_ 이탤릭체 텍스트 _ + +~~ 삭제 된 텍스트 ~~ + +위 첨자 : 19 ^ th ^ + +아래 첨자 : H ~ 2 ~ O + +++ 삽입 된 텍스트 ++ + +== 표시된 텍스트 == \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md new file mode 100644 index 0000000000..e6e285d707 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.1-baz +title: baz +--- + +## 이미지 + +링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다. + +! [Alt text] [id] + +나중에 URL 위치를 정의하는 문서에서 참조로 : + +[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## 링크 + +[링크 텍스트] (http://dev.nodeca.com) + +[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!") + +자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정) + + + +## 각주 + +각주 1 링크 [^ 첫 번째]. + +각주 2 링크 [^ 초]. + +인라인 각주 ^ [인라인 각주의 텍스트] 정의. + +중복 된 각주 참조 [^ 초]. + +[^ first] : 각주 **는 마크 업을 가질 수 있습니다 ** + +    및 여러 단락. + +[^ 초] : 각주 텍스트. + + +## 정의 목록 + +1 학기 + +정의 1 +게으른 연속. + +* 인라인 마크 업과 함께 2 학기 * + +: 정의 2 + +        {일부 코드, 정의 2의 일부} + +    정의의 세 번째 단락 2. + +_ 컴팩트 스타일 : _ + +1 학기 +  ~ 정의 1 + +2 학기 +  ~ 정의 2a +  ~ 정의 2b + + +## 약어 + +이것은 HTML 약어입니다. + +그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다. + +* [HTML] : 하이퍼 텍스트 마크 업 언어 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md new file mode 100644 index 0000000000..80ef3933a4 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.1-hello +title: Hello, World ! +--- + +안녕하세요, 여기 엔 틸리에 :) + +## Blockquotes + +> Blockquotes는 또한 중첩 될 수 있습니다 ... +>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ... +>>> ... 또는 화살표 사이에 공백이 있어야합니다. + + +## 목록 + +정렬되지 않은 + ++`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다. ++ 하위 목록은 2 칸을 들여서 만들어집니다 : +   - 마커 문자 변경으로 새로운 목록 시작 : +     * AC tristique libero volutpat at +     + Preisium nisl aliquet에 대한 + 시설 +     - Nulla volutpat aliquam velit ++ 매우 쉽습니다! + +주문 됨 + +1. Lorem ipsum dolor sit amet +2. 컨소시엄 adipiscing 엘리트 +3. massa에서의 정수 lorem + + +1. 일련 번호를 사용할 수 있습니다 ... +1. ... 또는 모든 숫자를 '1'로 유지하십시오. + +오프셋을 사용하여 번호 매기기 시작 : + +57. foo +1. 막대기 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md new file mode 100644 index 0000000000..ecaf1c0d11 --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: version-1.0.0-bar +title: Bar +--- + +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md new file mode 100644 index 0000000000..3b02bd716c --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.0-baz +title: Baz +--- + +## Images + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md new file mode 100644 index 0000000000..ef91d00826 --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.0-hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md new file mode 100644 index 0000000000..03b948629b --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: version-1.0.1-bar +title: Bar +--- + +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md new file mode 100644 index 0000000000..79aac52ca6 --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.1-baz +title: Baz +--- + +## Images + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md new file mode 100644 index 0000000000..3a81461691 --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.1-hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000000..404b11d43b --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,11 @@ +{ + "version-1.0.0-docs": { + "Test": [ + "version-1.0.0-foo/bar", + "version-1.0.0-foo/baz" + ], + "Guides": [ + "version-1.0.0-hello" + ] + } +} diff --git a/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json new file mode 100644 index 0000000000..48287dffc3 --- /dev/null +++ b/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json @@ -0,0 +1,11 @@ +{ + "version-1.0.1-docs": { + "Test": [ + "version-1.0.1-foo/bar", + "version-1.0.1-foo/baz" + ], + "Guides": [ + "version-1.0.1-hello" + ] + } +} diff --git a/test/__fixtures__/transversioned-site/versions.json b/test/__fixtures__/transversioned-site/versions.json new file mode 100644 index 0000000000..542b187dfe --- /dev/null +++ b/test/__fixtures__/transversioned-site/versions.json @@ -0,0 +1,4 @@ +[ + "1.0.1", + "1.0.0" +] diff --git a/test/__fixtures__/versioned-site/pages/hello/world.js b/test/__fixtures__/versioned-site/pages/hello/world.js new file mode 100644 index 0000000000..838f36bb1a --- /dev/null +++ b/test/__fixtures__/versioned-site/pages/hello/world.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class World extends React.Component { + render() { + return ( + + + World + + +

    Hello World
    + + ); + } +} diff --git a/test/__fixtures__/versioned-site/pages/index.js b/test/__fixtures__/versioned-site/pages/index.js new file mode 100644 index 0000000000..58dd9accb1 --- /dev/null +++ b/test/__fixtures__/versioned-site/pages/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import Layout from '@theme/Layout'; + +export default class Home extends React.Component { + render() { + return ( + + + Home + + +
    Home ...
    +
    + ); + } +} diff --git a/test/__fixtures__/versioned-site/sidebars.json b/test/__fixtures__/versioned-site/sidebars.json new file mode 100644 index 0000000000..49667e47b5 --- /dev/null +++ b/test/__fixtures__/versioned-site/sidebars.json @@ -0,0 +1,10 @@ +{ + "docs": { + "Getting Started": [ + "installation" + ], + "Guides": [ + "blog" + ] + } +} diff --git a/test/__fixtures__/versioned-site/siteConfig.js b/test/__fixtures__/versioned-site/siteConfig.js new file mode 100644 index 0000000000..e64b9989cf --- /dev/null +++ b/test/__fixtures__/versioned-site/siteConfig.js @@ -0,0 +1,7 @@ +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/' +}; diff --git a/test/__fixtures__/versioned-site/static/css/basic.css b/test/__fixtures__/versioned-site/static/css/basic.css new file mode 100644 index 0000000000..e6e089cbfa --- /dev/null +++ b/test/__fixtures__/versioned-site/static/css/basic.css @@ -0,0 +1,378 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; + font-weight: 300; +} + +button, +input[type="checkbox"] { + outline: none; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp input::input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -155px; + width: 100%; + font-size: 100px; + font-weight: 100; + text-align: center; + color: rgba(175, 47, 47, 0.15); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +label[for='toggle-all'] { + display: none; +} + +.toggle-all { + position: absolute; + top: -55px; + left: -12px; + width: 60px; + height: 34px; + text-align: center; + border: none; /* Mobile Safari */ +} + +.toggle-all:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li .toggle:checked:after { + content: url('data:image/svg+xml;utf8,'); +} + +.todo-list li label { + white-space: pre-line; + word-break: break-all; + padding: 15px 60px 15px 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.footer { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a.selected, +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, +html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; + position: relative; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle-all, + .todo-list li .toggle { + background: none; + } + + .todo-list li .toggle { + height: 40px; + } + + .toggle-all { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +@media (max-width: 430px) { + .footer { + height: 50px; + } + + .filters { + bottom: 10px; + } +} diff --git a/test/__fixtures__/versioned-site/static/img/sakura.png b/test/__fixtures__/versioned-site/static/img/sakura.png new file mode 100644 index 0000000000000000000000000000000000000000..e10909398bc26a8dc747cbea0dd6479ed5a84aa7 GIT binary patch literal 79340 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 DKbw08 literal 0 HcmV?d00001 diff --git a/test/__fixtures__/versioned-site/static/img/slash-introducing.png b/test/__fixtures__/versioned-site/static/img/slash-introducing.png new file mode 100644 index 0000000000000000000000000000000000000000..83945788689839aa89925a581f35d7abe4b546f5 GIT binary patch literal 15983 zcmc(`1yEeux-E>m26qXPpg{rzx8N3>V8Ja|XtZ$;5Hy6~?iSo7xYM{p2-bw)?*Ag$ z`|N%0JLlf>>VL0ZS3&ivUfpx9Dc?7~F~)qaq9l!pMv4Xl1A{3mBdH1l19t(u&p?3# z{-41`A;Z83^TQC+sUu#MozIMdRuP z&FohzpW=i+)@8J3`4)lC4Zsz9EnA}7WnO1@dvjZ90`>vwVPV$(M@vhufR}|L$B(R} zykiJL0SbRX!NWfml`Rdq`&Z=uW!Ibm>kE zFp*v0<_rVAFP|Gql$Ec3$uNU(T9O>U4)({AGEvZAAVwBLZUO${2wx+y24n;jqCH%H z0N%->vj%(;gM3vF$_Q8nt}{sK+x%&4P~~XV=vcMSfM4%T+DajAMYp=f5ufgb1|70mnahD^AVL zrH+F`7uSE%Nhqo7HKyCLY^ip-TCKBO`1qEac?m zffJjX=FcQ`b;-!FF)&hy3HW>`&dyvct*x!UcX(1uN0`i;3bf#1VqjpPq0#2QYakbY zmKYeqa99wX=n^^z$q_*vo#sS%n9WZd;B7QD0@5uGh-~EfBGKb7vSkSHEiq%*y%}4< zWTMi+x(rv$?H-qxmoHwt$f-rHM-Ha05wc`rVuGWis}cGj1z&*D&R2JD8xp*OV85ci zLaSxK(x6-xSZ9#f2Zrzk_mH3u3y;9D6M-`k#E)ZrQTUKFo|tAc@jmLHz7zMQ8H5NGYiE-?80NjL-Vw0thd`oPUM%=NGk&)bVXC%BXIDkETwSZykf)B*$a z4qKo@*APAX?yx>=&+3SV8R#4C9`)x--F*{_mM9KU z+J2K~CsbWCmfWUF5i%ww*;Azl;%f?x#B=McBh&~x`^TAW29NBN``HiWB#E>Pp zeyym##e+Wv?jar|sX@eEt|{d7NN_RzUU=okK<~|xXrUSBzzx3!=pjrv5`Y{A&_4v^ zGP6iL^h3L`Lp{g_1OWpda-00)Hk!YE4Z?}S|G5a~_dQmbzrq&+(03Gms1Wc;^}~2Q zTwA6T`i%%=BY6mUNfw2|myV^vmri_m=G~B&mzQhyQ=_1vq2c!ScKu?q0Fu|-+}zqK z?Ba$^YM~0zp;N6tzQ`CyK`dYq|B9lkTBy!O1xBsXX34Xs!XSxvOxBM6)l78+i5PM= zM;_CJ*w!w5e!D2fQnH4O;iMA6-DqK9;fb-kyStPWl6&D(ZMj1AqABZf1g~%E#Z#5- zz+RCOwP-Lz2{aEzgY!4#O!S`hx7^v^S7w)^i}m$|IpR07eDq!tr%4v?#BbuumuEK0 ze?^Ih8H@%3{ zWLj^Q)dp9Rke;3%7bjs2_65H|QC$eg%gUk^6<1xDu;lg)gNbmuUU9LkS2{RTJY{{i z(H(oeF6Xur|GpXdgNbEI1?1-%%fY(}A~|YqcGOT`6O|xwo}zb;X)wOCBS0M`o=Mu) zlh7+VfYEphgU>6gSRyMe-yNCh7VT0dAbl zn*ukyCVoVw#M&v3T4{Bv^P2Sll}L54p8jHi8|A{&nD-(LjBk6PYVPyj$57E%Mi>g#I?fNcd zc)Q~dA7zbCHHmt{eiY~bm6J+cczR;3;4{T1vGmMO?=j9z%CaCXS!P3s!2YhcO4HB-p0e=R&#GONfPg?#{X%k$SU20mn#BL#hE2-42rnjODm794cW^=< z#UjGPNxcNs0!WB#UwbuUae>(^*Fq$ND%v@rT$7w+S)C*%yXq1Yug$M=nH4njcp?*d zF%T9XYf@L0Utxc@;U?u|l**~782h2=mg&f#AMy5x&;rN*^!yTH$c|cyHhOZ4sO^FvQLP~V=auib1}$&I5?97e z3?diYXgG|>&q;_Cn`-S%BWlLK8K~89(Mt%We6V|t7yyp_YeckW=$Q5G9Q;bWnvSwFTUme-^E-)hU{QSJ7 za?Z{Vzm9P~g=PS$^2x946gf8;zO_fbVdUE7#E?d}RnjQw=FsI++vC-jL7u7<;`snu ztXJO5Yn_F z)1%O<&8+O!T#k+Uz@Z_>xqRvga->ORq%xL@FB*_Tp!h4(5YqSwtcSASTg-_2vpc+L z-iq=*>}Y;30#D>Q58?xmbAC0T`hzivEi2QDbE8u_5dm@4a?$+v-Y6b=dhK5uEK+c;#6Z2`G(B@ zk&L0sCE{0EF0=L!2sG`+N>IFyi>sH3MR$jvP|`;4AGx2h`c@p32b z+GiyGC>3f!@_&_4t)K4;9?3_u+MRffSAZ)f!cBmioWd*+3II&Z-cDWj|r_G!p zGCckb8y0=BblOS{7X}9g;4pG_>VT5Q7xzm=MuzWDtm9YktTlO+FVZl|rG& zh43F|+U>A^ooN$k`KYT3(|?c&8D1EQJia*ksqACg%m|_uTGheW4TrBW%#yosp% zxEM!HrD*;TZ@*VM4mBH5f1|8`E8N`{2`wM9>`Nhz>FJRw)?E$iNd$3J_LCurqfD=C zN%*wTEvCiJxpgw2e?;j{iU;R4Mq!o8-u~P*B;7})unY?K!Z9f(m_3&hyducTtpBo_ zTCs(-+nk}$2%~Ju%utv9 zG$`UGC~ebue}xQaA&>9e1hr9S=RA|L{_Vv&qzrvvUA{plVKA(0dd6S}#$mhd#nJXI zdus#uwh7slN=a;X_r)_)H1y9+h&^;U4xZ_U&+EB3{|x?vxTBNb7!m#NDb5XH*w}B+ zrtV8VuQxbCVU{wuZU%k^3>ud@n3aE=p(1f}QM>4E;_-~F-x0rBm2c=}OCa#kFmx@= zK9*W(AC5tXVLQ)5V^d}-QQmq!H5KuSVX2Yo?>Ra*RIxa!CL#I;$wW<a}9 zI(}0u4(OqD`(2Z1hxPFUvzFG#P2;97-3%}7V6*DZ?h3-f!J33(rV1_0POo;Z(LjF{ zg*tyG`jG4&t9!(wx{$YuACJY9+ozgl%&GK*Z%-z2a_DkZFE6*!$+pkFeGOpMt-aag zZ8NIdlI+`vfDwAuDA9i>1m+XUpwx=!`CO!+_B*9=6|Z5X5%`S&vmGZctEf0UU8;+R zhc}ukV3D)HnC@BmZezgbGQsC^s@$7^l+(@7D|S(~b@gjp|0bUP^O`=9k}(9k;wLolf7qcYOc=P8j@r8$mr^$EPOgEy2)A zCYvIIxm47~`vX5*mj=hR9`Jq(ul;f}k)h||oJIQWVU$nG$B*20qpPc{S_bYLr!$68 zA3gxYRy#*H5&PZU^*$!p#o1Zte9?)Gjcuk(|N3gD-1hBT1FzGm!31`)v$vL(zER6n z7T7!TT40wwQ;Z6=UHx@xAy!Ozt-qDbEY!4&$hu2EQVN_{$LW^H{fqQb-W%kb4R)W)iS#=Js$mbvi=>nxV&f2{k7?TzsT518 zE)#i*e}^uc+HZAB_79J4iK-Z~$f+M8BZpAkU-W+X@ZpNt94Imkye~ImVsLLq#>U1* z1&_|vRM0k*#06g1fhw=K_ z+*||=p)0qA>pV6QGcz;p-&W^Ph2U6PA7PdN`;*?>6kx0yo0>$fe^$MG`7$EUzV#AV zTbIN8KKIvTyml(IerYi=F~Mf#hIdB^RGtU0iLtN^F1w_9jv$cfNwe4WnN4|1PyO9q z(|+sewC;)P+^(P*Jw4EPCGRksrT+Q$#5xF=Jd|H3=lAv)%9Y^>VS8a_R`U4TGMQ%M zX3w<^n1y9|_Lh&SsX}Z>m{?eMC;1{?x2H3m9UV6}H{K`NRCDw5eDp>FoV2-#LE zdrRxpg@vfU`H5rSe}xE1_EulN?lA~TN=}w{ZQ}orxY%BU4i>`j?FD2BDYHceo0!l( zX?A~Y$PY8t43lhJy|!~#34YkoW{=aNm<<6cpPR!UQ^khh-I|rVv$~y`@-|=;C53>k z=@$s>IV+e1Ekm!VK6uT@$jDKlb3IW}7|&B+5kw>;%+y~)zYJM~T0ST3!MT3+jxmBE zEkRk{hPmM#_0vSP?0&vqsoabo+U)fWpExuVT!pqBKL5V`{>Ag>@dhmH?4x~s)a=g@ z<)6mO)x7=%4XtZl69N=ZFA9|9932*7R6tEF!w@GF42O$*cXxM^B}wboC1sG0q3E!K z{TK7w2>Dq*l|;$D;&BI6uupWlySW5r23WbwT4luBF8j+ZH8wMM3vIUx7f|Fp|d%AxMy z$5a?+=2YqAi`%-p5JL91rzFuI$apz>wCZZ5eaJOZu8dR}g@jTCvin*7&M*fwRX-3s zV~T>w$;n@FY;A2Vq^aHu{u-w@3972m-soNa?lhM<~i#*Dq!AwdCH%wEBLdp>Mk znW{6BSt3c_UH3Cz(K9dvqi6T)JrvoNDZQeMFP5DQBib1n9$}nFNr{jLq>|Rq zLd#)xHnz65*4LxwDZfz?`%j)_6aq>|boAsIHz{TYEzH{DT^$8!8D6uOnpe1?R0C$POjA0FyU62h~n_ zm0`-k+_Dy36`+B@E$UYid5KibetL(|bKu;x#lha%4+2C*~(E6K|4S*Gaes<9xZc99LIY2X#`-s8ojI8k$&W&FQeT0G1c=5@;}E!=Y3J>%MTyZ3de!K;ul*)tdg!?Q<5(B%lhgnM^xRh9|mfJ<07 z?etG<{QN(ldonuziSVv#hmhm58&3Z0gquzrsCrFx_7@l<6Mj*>|e;~$Ykl@<8 z{{G^csCMWT$SF1L5-(7 zGgU(tqEJ;8rewTW3~4nzJ^c5Ns8LZ-OQ;k#S^tiBDZ+pt@NWpEV88!LC~RR??91S&eUe4X!UT?f> zsH);>$BgO?Q1^mDGEI6TyL);X8yWyi#=_6;0i$Y?0cObQGn2lgloU8i0Bh_zn6;{b@qr z*tobL@zo-YV(Nr&$t<(`kMYb}wRLq>qfStlYIRLyW(HEl#Kgp$(L^o_OB(D4F6u#; z0K`g*9mRKE-_5h`lr$N!vQ_#f0xw?*wN)Z?wdLd*a zBp8z4`sQzKH4zha7T0)U;BafQpdHAc@H(B`g900*s7|zP^AoFfyVPFZVLZKOg`AOLOZyZ*Y3P6%`h7 z3Mb*CAwWKFf;HT_#rG)ayCUToGYbp*#rjuI@EbdQR{CYBao)~X zKLv(?o12@N8GUci>Zu$<-1g{V`{>4C0zCY4US6A;`GEmBX=&+t=+;)k$B&X=Aos?> zUkt*-!-su&HtjnSvu=t6Ef^oq<4h{LZ?LhoRmAiMMx_@7`TCTd8|zb99^27phx|p~ zbEPT-vqexEGJ9jKp{ua#;P#bJZwR)Qu-mtjD4#&DQ;qQh2Qx>yVYi#Q5S6c0s8rOQGfSMt3ALnA&ty^WYisvr#=sZz(yLL+HtG%W7-E z`Sgp@arp3{?u|r*TDtaixO^%Zi}70LaF{^t3x=i&_|25&P*VZ0EG9_?vae;Xf zWrX42OvK={dka(}2Frf%$WIna4BOIZ2gkCd`(fKvl$Dh&EG*R2;@a9o^j42AMOmvY zjErbrIJ|oY%rq0Q#8_DoyXL+a!Rwb|2&x+zir}qeh-W@wXTSehHQLinY6Qx(yO6I6 zP;z#DZsO2wzbx22rmmwS>zxa198S(hf8XXvW{!`^(i$s8*55TJ~)o3DPaP=Rx&-Rk+`8_G+Ya}#dy=WK<^?tINb6EF{hlnIfMSeBdu z8xau^3f%5a+k<30Hy?{W838@Fv0*lGDAjtB$Ct!ozpP-$!#z=@_ZN4I11g~e`6D5w z>+8C1gjKe+Az8v(B2jmmsQW7Un$+4Zd`d`gJzAIbXZV$gk9wC|z^5^}fWB5)$;r=8 zs@*#{7(O!X+fJ45liApq1cOHoL-{oypk8=ojv1zfxp^3UfDz&%r=QqTx_gw;Q08sZ#s+}0vxPWkYPTy zX;5%*2i4)(ndTFG2%a#lfIw4bCal|FvmsTXHtYtpeC&nK_QGiS4eO=bR+C-7&naKC zWCp^iUYv~-1ojTT!=|8I#Ovw=0?FPcF;pHcjLHKNa$^N2^GcK-fN=+IGLA*+JLr1cR-IL41)`1#yQWJ)I$S6Us6d4<`E82?4HlA3R$Meidn?Std6V&$UVl- zs6^QWBj>6X>It98IaO#YtOyfxGOh9Gj2WBu3dT6Uic}uG3eHnI$i=C2baFyRL4i5q z^S*HdHUW@FU?Xp@&(%!F(!2fa03QXQ!2&p-<5gi%QC2Ao{n^>s`USAA9MGcGRaN0W zRsmZdSXfs$(?E&)mAB7PMMcHjJTERTPLdXOV0(8rC~CIRnR!VDGBs6GQ!~{p?6fsP z@g||5;E5Lmw$(9~5`FG960-VZ*WzIm{;O@z&a3l{ul|e_iU$PIuU_!+)te0xPDe1T z{UR0Pw=<5<{M6o12k#9t<*-}lPvrbvrd}ZbA7pCkxa|MW*cXl^W`3a&!($lFjkiMY61cryBCuWj>+ZXI~CiiB|nh6F!vFlbY zS-H1GuMpHa-LpYq4DlRfB_!a3$PUhcq(5%f=gV@CKtqxcA5YK7=<4E9rdtqz(DqVD8CLN5EUEL0i&JAdXb2&GyPeqku{#l-uo{l zmcvJc$Ip?y`d}@M>%xqY1Ld#$ivj}?9K16~4laNEu;xQLU#>Jmx6r;=?8#>QUn@#yA>EL!2SIBb4MfL=*K-A zrJ$Gll0cGMHNOoBi+T_aK2~SQ3No4IQGDm*-d66=EeUn)1EkW~YWi>f2Ccgy6+J51 z=ym)(?krV?N}5x^&~+v_e`|+5Fg@5UD`TUk?4Uo;7)P$uEH_9^NRUqJnXj{_x)|S{ z$d95BK{TZ+v~<$XcpCZnpVs;G#$XjxlZyQ#hv6qr10(c|^QT6jM+ zTrj`d+fvO~Xlz*aG+n=yV~fQmLJl|xz9RjTk*OXYULE00%EEoEM5nWVoqdsg z3^V(uMMkX--ExI>pc0cDK)H{nyt`eaSA$wj0eW8?bZ&Fa#0WPz-PPmYM*L=f}>DpFMRSzkq-Q^2OZb zN@G^fOoXtBClv)A4@SzQMGq{6n)C#aKDG}8->rw%MExly{5Sq7I3t;ds+3ZaEmu|N zbac0$hG*=5zbIw3iuvW9O3ZYBg%_UZRDDyZf(1pkKxBO9Iff(aV;ITf>4or_DuVavhSQ;(a{m&adBW2T5Foibpw#OI0;Y8J1oqxK*q6E<`ygg!=)bowzgdlhF5?` z@;|V68Kle|S@E1dPpLLaC|;;hDuj&>C%hX!N=7zZm;^mDvCOzuG^Qu0l!dSY2J{v= zAB}%M!Hv8~fkv`p?U0&JQ&ST_8WNsAx3@FxDF6aGw~8+`#(SfdQ=$72= zZq!PsAyPmz0%BuhA5oKqdVK3S=}rOI`tZm|hF)Ngtm|)3njo98^r^0c?t2 zPcg}Oy1Kd`cXGM0Z0FlQe)tRYO-q-{Llp$T#=~>FRB4!W>8&NY&j`{lNrPB_%WLET z|1iLX1eSkrP$n9+-vYb|DIqxy3)1Gs(-Ez{?_t7#gzoN~qcPpL9^Lm%(yecy|T}iCBp1S5i`1oGp_}i{F z^jJ)HBb-#HlJfGsoEEHr>6J~ilatf-6mr^z^WYklRRDJ74Fp zurMT~5xr*Z!(m?3I(vCaVGuR@E8ZKBYU3Y1iypCG?%PC19o5ma-ogA?KEI?U6w?G@WWXAyT z`p93j<>cfH4ObeR^b^>rt`}Cmx8A2&pz!vHSsePFlOq1MC;VyE<6;+nKYp42qRuE| zYa0Skpg?bjlX=1J?j(N6z>-8jMBH6zYpbk0`Z<>-pP=M@y*sksdd!Oj{9bS7S1OAK zq8~5-ClNk)Ll{)oGCCEV<2+cNo~-vVQ=g^DEx&U9rr=XvTwILX3hctUT3cNJquASz zc86;i`gk2ov(9yfM5=8iJBnGHnlJzOAlRDFi{D0?Lx|Tk-b3_Yht7NY+i{XOn#H<@L|fqk$7!r6-6GMt**NE-s+>1;7O-6Vt%-^jU6#L6U{~-OW}y336&T zyhoIW?J@W6LgIk_Hw7?|^&YL^t)fLT{1TGj{}PgD-+j=MJMh=E5hwAAy|_8{ygE}9 zPH!_C`~;X2dwO~XiU!WA^!;`M5?BpuO`GDDeD9HSo6VT1T1N1$qElhC%JfJG30*D@ zR)d3sV`BE$Tl*RuO(t5v1`I=s3OP3THqBiABG6Okl4EQ`BBOa%N%D);X7_{RdxKQo zGVo}1y5Li2$?BIk4;JCFu?ItU1%Aw1w3;5|@)OzbSEsf@LP7wd#mt5?tXJ)nm z7^rnV1_tw`M(1_81h#m+rrPVKeYhbM-YCDw7p6>mA2J?%Ie*&8 zJ3r>ucu#Amj5EG(az#AY*qg5jZ_eQYcxtYH)S&ZX#01A zV)_|N4ZRcZ&fBDy+V=S;9Dwfp)g`fB+O8dkXXv6^gX~;DQ6^=miRcgqm_M|%csa9f zzlSgG%+xJ5ZE+?4<9h=`|FX&`D=f6KA^{Uv|3@bGH+!25@p2nS6++kD#vEP=7JUT~ z3#P2J%QS|XYZg-(PS>?L`CBJ3kEP}0YqVE7 z&hZzl9RNYxuiKwK!;v^QCm1KH!SlO!vbJVw(Kavu)GaXsYqU?QO!3w=Ne{mEplk8J z^bkMDkcyaSv;qV8XG2aX%3ogiXd=abveyLZ=v%tX_E#A|U|XCR4;JiQ@7AbRu_;Tg zj?;a3>}yTOdk1yaxZ?b=BJ*T_Gf5=K6wzsEl<{(ic{KUJ3bC@XT3TA_@&xESAlCzw zXdtGVsw#kMUVIlK=ZLh*fd6-9RqL0IbBwZ$Ut;X1GE6E4NYgoppkKVX6{!G4I@3{s zT_1OB8#FgJ2MC;iMB*^NxQG#KX=4+x=I7^!mko#PFu%Nvr3k$AK4Y%~zI zO2}MU|E#!JR|jaP$6`pM(fH7kQ|te_jUJxjU!qUlFa$=0%xzdCoeBMJoyf>^8kW00z zSf8lN@H>J9*gNI>gX2W+=9@7KOb_JUXx*mKp_5?05)wrl^S7O%zwG{d5rW|5PR_M& zBYkUOhW)Y1|9XIC;mhegx_YjolmMXY zR3iCJ!1oH$Mxh$MqN$eZqG|l%N)AbEyh=S!p@3A_5K%vvKmH=n7mV|3jR)Mhv$Idr zu%O=}M(}Za>%Uow|K%9XG@kfjJCy-%Ens<-qjWV>MkaiIAhb{7)SrDnU6cq<98B%1EN`r=r`Kse3A1N`v703cC7ph!6qUwgCt zqawfeT=pe6VoFZ3$uxXYlc%uiOO(CKKn2xVS}I8@J-;E~iux5%kY|1!bojhIR)m&m zTddp{{H!w%0u7DtrriP07A3b?BIP-$w!TZIfUIsH{_)IfKy$#MiqB$n$r7mKEX7CR zp{BKEPwEDG2Z>HTyYpKdN-raq)i0%2aH?V5f|lJWcjq+vCJKTSzap*DG+k6^!G znHX3YC2I&9w5nKaHl)x~9nN_6$T$ATyWbm4gh}m|SdPTJ+e0+I40iaPc`bjlh7??r zr6;&w^QNS$ZGPI0m-Tk(EeQ11m)(56pVRM6WYZTCFBYcS{-pB9w^E+|pFEkdu&(%* zL6wj;{IzFdhC@cy)r`2Dg}t}mM1YXaBy&aJ0CM;=^lywWKe`4D*^Tn7RF6B zXv!D9nw*h@1Va2T%#xKHpzc@7Fx16~V=o5NUqEym=Di3h*%{;bKW%g6`C$=BO>qAo zPNCLMHQoaR?|p2DPTJVvUDu%A#EbiSdkoMg=Zn{QqeD-i+NYLD6c78choc4bQZj!6 z5LSo?39+!SI;@4T`vE+Qhr$QUwt26Nty1Dsb=1dKhtfj}S~vxFglCEhw~ z+l4r!e%np{p}Rg1PJiAXe=yCA=MGpvAbchnYyaY)NY8Qu${`WlNj(j57SCctEJM9e zP_lX_cut2v%ac z4GjV-)#9n@T4ah0T`Q}?sfYfeKtqEf4<;U~qlgU{5W@AUcN=FOMl;38Q2&h8K%_&M z&_Hw$WnAsQ5ljtC=Yq(h8c{)6em*}YO`UoS;Cn6omaR9-7K0OQ@60?QInpbOGo?JIbuKii)UtfBiS1x6dPWL__}R zsD}t|<_mM7Yf+2Vo}mn_MBxB`h(A3aZRBPl*48eN!8ogAzd20-AiOAlB4gi_BL~9?nm_L4DJU?*$?yu7V%+bE7G{;S|J^aTto(ongBdf)mh5??} zcLVLmf<4IY>*1v{PXFY{#N7E}Z?J{C^O?Im?y{zM?&;QmKC;BX;Sd&Q;xiV>h=9nK zsDJ(boh6IW?Ds#q@q zq@uba`0pYvk~8Mv7ZGSf4rHRX$3{#5eD+9h_8Llo8?_wre7)uE#n_D^BtH$gyuRjk z>2eSLn0n*`7;DS!h4Z3=QuEKv%L*b-$amO%`uxkmAD2|-ZjD`s7Y39Q_x`^}#E}T( zAefzz;Xq@XjSDe;vWSmBfsc=`u<*o^NLO=ANP$h=^jyh=08P!*~DfZDyM5 b_wbd&t}l-+I5&WU Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md new file mode 100644 index 0000000000..3b02bd716c --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.0-baz +title: Baz +--- + +## Images + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md new file mode 100644 index 0000000000..ef91d00826 --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.0-hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md new file mode 100644 index 0000000000..03b948629b --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: version-1.0.1-bar +title: Bar +--- + +# Remarkable + +> Experience real-time editing with Remarkable! + +Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. + +*** + +# h1 Heading +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +*** + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, + +Remarkable -- awesome + +"Smartypants, double quotes" + +'Smartypants, single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Deleted text~~ + +Superscript: 19^th^ + +Subscript: H~2~O + +++Inserted text++ + +==Marked text== diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md new file mode 100644 index 0000000000..79aac52ca6 --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: version-1.0.1-baz +title: Baz +--- + +## Images + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + + +## Footnotes + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +## Definition lists + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +## Abbreviations + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md new file mode 100644 index 0000000000..3a81461691 --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md @@ -0,0 +1,40 @@ +--- +id: version-1.0.1-hello +title: Hello, World ! +--- + +Hi, Endilie here :) + +## Blockquotes + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar diff --git a/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000000..404b11d43b --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,11 @@ +{ + "version-1.0.0-docs": { + "Test": [ + "version-1.0.0-foo/bar", + "version-1.0.0-foo/baz" + ], + "Guides": [ + "version-1.0.0-hello" + ] + } +} diff --git a/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json new file mode 100644 index 0000000000..48287dffc3 --- /dev/null +++ b/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json @@ -0,0 +1,11 @@ +{ + "version-1.0.1-docs": { + "Test": [ + "version-1.0.1-foo/bar", + "version-1.0.1-foo/baz" + ], + "Guides": [ + "version-1.0.1-hello" + ] + } +} diff --git a/test/__fixtures__/versioned-site/versions.json b/test/__fixtures__/versioned-site/versions.json new file mode 100644 index 0000000000..542b187dfe --- /dev/null +++ b/test/__fixtures__/versioned-site/versions.json @@ -0,0 +1,4 @@ +[ + "1.0.1", + "1.0.0" +] diff --git a/test/load/pages.test.js b/test/load/pages.test.js index b00d554924..7a76e76a82 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -3,11 +3,7 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { - const pagesDir = path.join( - __dirname, - '__fixtures__', - 'simple-pages' - ); + const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); const pagesData = await loadPages(pagesDir); expect(pagesData).toMatchSnapshot(); expect(pagesData).not.toBeNull(); diff --git a/test/load/utils.test.js b/test/load/utils.test.js index bf9e54e463..8264c71e7e 100644 --- a/test/load/utils.test.js +++ b/test/load/utils.test.js @@ -65,6 +65,7 @@ describe('load utils', () => { versions: [] } }; + const test = {arr: [1, 2, 3]}; const variable = 'enabledLanguages'; expect(idx(a, [('b', 'c')])).toBeUndefined(); expect(idx(b, ['hello'])).toEqual('world'); @@ -79,6 +80,7 @@ describe('load utils', () => { 'en', 'ja' ]); + expect(idx(test, ['arr', 0])).toEqual(1); expect(idx(undefined)).toBeUndefined(); expect(idx(null)).toBeNull(); }); diff --git a/test/loadSetup.js b/test/loadSetup.js index d16f447c38..b990354f6c 100644 --- a/test/loadSetup.js +++ b/test/loadSetup.js @@ -3,14 +3,24 @@ import load from '@lib/load'; // Helper methods to setup dummy/ fake projects const loadSetup = async name => { - const simpleWebsite = path.join(__dirname, '__fixtures__', 'simple-website'); - const customWebsite = path.join(__dirname, '__fixtures__', 'custom-website'); + const fixtures = path.join(__dirname, '__fixtures__'); + const simpleSite = path.join(fixtures, 'simple-site'); + const customSite = path.join(fixtures, 'custom-site'); + const versionedSite = path.join(fixtures, 'versioned-site'); + const translatedSite = path.join(fixtures, 'translated-site'); + const transversionedSite = path.join(fixtures, 'transversioned-site'); switch (name) { case 'simple': - return load(simpleWebsite); + return load(simpleSite); case 'custom': - return load(customWebsite); + return load(customSite); + case 'versioned': + return load(versionedSite); + case 'transversioned': + return load(transversionedSite); + case 'translated': + return load(translatedSite); default: return {}; } From 0f38ae39793e675a25edb67783a280b6abc7a78b Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 20:41:04 +0800 Subject: [PATCH 109/135] =?UTF-8?q?feat:docs=20translation=20+=20versionin?= =?UTF-8?q?g=20=F0=9F=92=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/load/docs/index.js | 120 +++- lib/load/docs/metadata.js | 127 ++++ lib/load/docs/order.js | 70 ++- lib/load/docs/sidebars.js | 69 +- lib/load/env.js | 119 ++-- lib/load/index.js | 6 +- lib/load/routes.js | 37 +- lib/theme/Docs/index.js | 6 +- lib/theme/Layout/index.js | 8 +- lib/webpack/base.js | 2 + lib/webpack/loader/markdown.js | 7 +- test/load/__snapshots__/pages.test.js.snap | 22 - test/load/__snapshots__/routes.test.js.snap | 201 ------ test/load/docs.test.js | 21 - .../docs/__snapshots__/index.test.js.snap | 593 ++++++++++++++++++ test/load/docs/index.test.js | 23 + test/load/docs/order.test.js | 70 +-- test/load/docs/sidebars.test.js | 92 +-- test/load/pages.test.js | 19 +- test/load/routes.test.js | 41 +- 20 files changed, 1133 insertions(+), 520 deletions(-) create mode 100644 lib/load/docs/metadata.js delete mode 100644 test/load/__snapshots__/pages.test.js.snap delete mode 100644 test/load/__snapshots__/routes.test.js.snap delete mode 100644 test/load/docs.test.js create mode 100644 test/load/docs/__snapshots__/index.test.js.snap create mode 100644 test/load/docs/index.test.js diff --git a/lib/load/docs/index.js b/lib/load/docs/index.js index eb906b9a10..ea061c052d 100644 --- a/lib/load/docs/index.js +++ b/lib/load/docs/index.js @@ -1,37 +1,113 @@ -const fs = require('fs-extra'); const path = require('path'); -const fm = require('front-matter'); const globby = require('globby'); -const {encodePath, fileToPath} = require('../utils'); +const createOrder = require('./order'); +const loadSidebars = require('./sidebars'); +const processMetadata = require('./metadata'); +const {getSubFolder, idx} = require('../utils'); -function parse(fileString) { - if (!fm.test(fileString)) { - return {metadata: null, content: fileString}; - } - const {attributes: metadata, body: content} = fm(fileString); +async function loadDocs({siteDir, docsDir, env}) { + // @tested - load all sidebars including versioned sidebars + const allSidebars = loadSidebars({siteDir, env}); - return {metadata, content}; -} + // @tested - build the docs ordering such as next, previous, category and sidebar + const order = createOrder(allSidebars); -async function loadDocs(docsDir) { + /* Settle versions & translations from environment */ + const translationEnabled = idx(env, ['translation', 'enabled']); + const enabledLanguages = + translationEnabled && idx(env, ['translation', 'enabledLanguages']); + const enabledLangTags = + (enabledLanguages && enabledLanguages.map(lang => lang.tag)) || []; + const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); + const defaultLangTag = defaultLanguage && defaultLanguage.tag; + const versioningEnabled = idx(env, ['versioning', 'enabled']); + const versions = + (versioningEnabled && idx(env, ['versioning', 'versions'])) || []; + + /* Prepare metadata container */ + const metadatas = {}; + + /* metadata for default docs files */ const docsFiles = await globby(['**/*.md'], { cwd: docsDir }); - - const docsData = await Promise.all( + await Promise.all( docsFiles.map(async source => { - const filepath = path.resolve(docsDir, source); - const fileString = await fs.readFile(filepath, 'utf-8'); - const {metadata} = parse(fileString); + /* + Do not allow reserved version/ translated folder name in 'docs' + e.g: 'docs/version-1.0.0/' should not be allowed as it can cause unwanted bug + */ + const subFolder = getSubFolder(path.resolve(docsDir, source), docsDir); + const versionsFolders = versions.map(version => `version-${version}`); + if ([...enabledLangTags, ...versionsFolders].includes(subFolder)) { + throw new Error(`You cannot have a folder named 'docs/${subFolder}/'`); + } - return { - path: encodePath(fileToPath(source)), - source, - ...metadata - }; + const metadata = await processMetadata(source, docsDir, env, order); + metadatas[metadata.id] = metadata; }) ); - return docsData; + + /* metadata for non-default-language docs */ + const translatedDir = path.join(siteDir, 'translated_docs'); + const translatedFiles = await globby(['**/*.md'], { + cwd: translatedDir + }); + await Promise.all( + translatedFiles.map(async source => { + /* + Do not process disabled & default languages folder in `translated_docs` + e.g: 'translated_docs/ja/**' should not be allowed if lang 'ja' is disabled + */ + const translatedFilePath = path.resolve(translatedDir, source); + const detectedLangTag = getSubFolder(translatedFilePath, translatedDir); + if ( + detectedLangTag === defaultLangTag || + !enabledLangTags.includes(detectedLangTag) + ) { + return; + } + + const metadata = await processMetadata(source, translatedDir, env, order); + metadatas[metadata.id] = metadata; + }) + ); + + /* metadata for versioned docs */ + const versionedDir = path.join(siteDir, 'versioned_docs'); + const versionedFiles = await globby(['**/*.md'], { + cwd: versionedDir + }); + await Promise.all( + versionedFiles.map(async source => { + const metadata = await processMetadata(source, versionedDir, env, order); + metadatas[metadata.id] = metadata; + }) + ); + + /* + Get the titles of the previous and next ids so that we can use them + */ + Object.keys(metadatas).forEach(metadata => { + if (metadatas[metadata].previous) { + if (metadatas[metadatas[metadata].previous]) { + metadatas[metadata].previous_title = + metadatas[metadatas[metadata].previous].title; + } else { + metadatas[metadata].previous_title = 'Previous'; + } + } + if (metadatas[metadata].next) { + if (metadatas[metadatas[metadata].next]) { + metadatas[metadata].next_title = + metadatas[metadatas[metadata].next].title; + } else { + metadatas[metadata].next_title = 'Next'; + } + } + }); + + return metadatas; } module.exports = loadDocs; diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js new file mode 100644 index 0000000000..6bffbb5db3 --- /dev/null +++ b/lib/load/docs/metadata.js @@ -0,0 +1,127 @@ +const fs = require('fs-extra'); +const path = require('path'); +const {getSubFolder, idx, parse} = require('../utils'); + +function getLanguage(filepath, refDir, env) { + const translationEnabled = idx(env, ['translation', 'enabled']); + if (translationEnabled) { + const detectedLangTag = getSubFolder(filepath, refDir); + const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); + if (!detectedLangTag && defaultLanguage && defaultLanguage.tag) { + return defaultLanguage.tag; + } + const enabledLanguages = idx(env, ['translation', 'enabledLanguages']); + const langTags = + (enabledLanguages && enabledLanguages.map(lang => lang.tag)) || []; + return langTags.find(langTag => langTag === detectedLangTag); + } + return undefined; +} + +function getVersion(filepath, refDir, env) { + const versioningEnabled = idx(env, ['versioning', 'enabled']); + if (versioningEnabled) { + const subFolder = getSubFolder(filepath, refDir); + if (!subFolder) { + return 'next'; + } + const detectedVersion = subFolder.replace(/^version-/, ''); + const versions = idx(env, ['versioning', 'versions']) || []; + if (versions.includes(detectedVersion)) { + return detectedVersion; + } + return 'next'; + } + return undefined; +} + +module.exports = async function processMetadata(source, refDir, env, order) { + const filepath = path.resolve(refDir, source); + const fileString = await fs.readFile(filepath, 'utf-8'); + const {metadata} = parse(fileString); + + /* source (relative to refDir) */ + metadata.source = source; + + /* default id is the file name */ + if (!metadata.id) { + metadata.id = path.basename(source, path.extname(source)); + } + if (metadata.id.includes('/')) { + throw new Error('Document id cannot include "/".'); + } + + /* default title is the id */ + if (!metadata.title) { + metadata.title = metadata.id; + } + + /* language */ + const language = getLanguage(filepath, refDir, env); + metadata.language = language; + const langPart = (language && `${language}/`) || ''; + + /* version */ + const versionRefDir = language ? path.join(refDir, language) : refDir; + const version = getVersion(filepath, versionRefDir, env); + metadata.version = version; + const latestVersion = idx(env, ['versioning', 'latestVersion']); + const versionPart = + (version && version !== latestVersion && `${version}/`) || ''; + + /* + Convert temporarily metadata.id to the form of dirname/id without version/lang prefix + ex: file `versioned_docs/version-1.0.0/en/foo/bar.md` with id `version-1.0.0-bar` => `foo/bar` + */ + + if (version) { + metadata.id = metadata.id.replace(new RegExp(`^version-${version}-`), ''); + } + + const dirName = path.dirname(source); + if (dirName !== '.') { + let prefix = dirName; + if (version) { + prefix = prefix.replace(new RegExp(`^version-${version}`), ''); + } + if (language) { + prefix = prefix.replace(new RegExp(`^${language}`), ''); + } + if (prefix) { + prefix = prefix.replace(/^\//, ''); + metadata.id = `${prefix}/${metadata.id}`; + } + } + + /* Build the permalink without baseUrl */ + metadata.permalink = `docs/${langPart}${versionPart}${metadata.id}`; + + /* if version */ + if (version && version !== 'next') { + metadata.id = `version-${version}-${metadata.id}`; + } + + /* if language */ + if (language) { + metadata.id = `${language}-${metadata.id}`; + } + + /* localize id */ + metadata.localized_id = metadata.id; + + /* Determine order */ + const id = metadata.localized_id; + if (order[id]) { + metadata.sidebar = order[id].sidebar; + metadata.category = order[id].category; + if (order[id].next) { + metadata.next_id = order[id].next; + metadata.next = (language ? `${language}-` : '') + order[id].next; + } + if (order[id].previous) { + metadata.previous_id = order[id].previous; + metadata.previous = (language ? `${language}-` : '') + order[id].previous; + } + } + return metadata; +}; diff --git a/lib/load/docs/order.js b/lib/load/docs/order.js index 9d69798e08..5f9f6c3478 100644 --- a/lib/load/docs/order.js +++ b/lib/load/docs/order.js @@ -1,34 +1,36 @@ -// build the docs meta such as next, previous, category and sidebar -module.exports = function createOrder(allSidebars = {}) { - const order = {}; - if (!allSidebars) { - return order; - } - Object.keys(allSidebars).forEach(sidebar => { - const categories = allSidebars[sidebar]; - - let ids = []; - const categoryOrder = []; - Object.keys(categories).forEach(category => { - ids = ids.concat(categories[category]); - for (let i = 0; i < categories[category].length; i++) { - categoryOrder.push(category); - } - }); - - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - let previous; - let next; - if (i > 0) previous = ids[i - 1]; - if (i < ids.length - 1) next = ids[i + 1]; - order[id] = { - previous, - next, - sidebar, - category: categoryOrder[i] - }; - } - }); - return order; -}; +// build the docs meta such as next, previous, category and sidebar +module.exports = function createOrder(allSidebars = {}) { + const order = {}; + if (!allSidebars) { + return order; + } + Object.keys(allSidebars).forEach(sidebar => { + const categories = allSidebars[sidebar]; + + let ids = []; + const categoryOrder = []; + Object.keys(categories).forEach(category => { + ids = ids.concat(categories[category]); + // eslint-disable-next-line + for (let i = 0; i < categories[category].length; i++) { + categoryOrder.push(category); + } + }); + + // eslint-disable-next-line + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + let previous; + let next; + if (i > 0) previous = ids[i - 1]; + if (i < ids.length - 1) next = ids[i + 1]; + order[id] = { + previous, + next, + sidebar, + category: categoryOrder[i] + }; + } + }); + return order; +}; diff --git a/lib/load/docs/sidebars.js b/lib/load/docs/sidebars.js index 92b0e16553..fd27c22177 100644 --- a/lib/load/docs/sidebars.js +++ b/lib/load/docs/sidebars.js @@ -1,34 +1,35 @@ -const fs = require('fs-extra'); -const path = require('path'); -const {idx} = require('../utils'); - -module.exports = function loadSidebars({siteDir, env}) { - let allSidebars = {}; - - // current sidebars - const sidebarsJSONFile = path.join(siteDir, 'sidebars.json'); - if (fs.existsSync(sidebarsJSONFile)) { - allSidebars = require(sidebarsJSONFile); - } - - // versioned sidebars - if (idx(env, ['versioning', 'enabled'])) { - const versions = idx(env, ['versioning', 'versions']); - versions && - versions.forEach(version => { - const versionedSidebarsJSONFile = path.join( - siteDir, - 'versioned_sidebars', - `version-${version}-sidebars.json` - ); - if (fs.existsSync(versionedSidebarsJSONFile)) { - const sidebar = require(versionedSidebarsJSONFile); - Object.assign(allSidebars, sidebar); - } else { - const missingFile = path.relative(siteDir, versionedSidebarsJSONFile); - throw new Error(`Failed to load ${missingFile}. It does not exist.`); - } - }); - } - return allSidebars; -}; +const fs = require('fs-extra'); +const path = require('path'); +const {idx} = require('../utils'); + +module.exports = function loadSidebars({siteDir, env}) { + let allSidebars = {}; + + // current sidebars + const sidebarsJSONFile = path.join(siteDir, 'sidebars.json'); + if (fs.existsSync(sidebarsJSONFile)) { + allSidebars = require(sidebarsJSONFile); // eslint-disable-line + } + + // versioned sidebars + if (idx(env, ['versioning', 'enabled'])) { + const versions = idx(env, ['versioning', 'versions']); + if (Array.isArray(versions)) { + versions.forEach(version => { + const versionedSidebarsJSONFile = path.join( + siteDir, + 'versioned_sidebars', + `version-${version}-sidebars.json` + ); + if (fs.existsSync(versionedSidebarsJSONFile)) { + const sidebar = require(versionedSidebarsJSONFile); // eslint-disable-line + Object.assign(allSidebars, sidebar); + } else { + const missingFile = path.relative(siteDir, versionedSidebarsJSONFile); + throw new Error(`Failed to load ${missingFile}. It does not exist.`); + } + }); + } + } + return allSidebars; +}; diff --git a/lib/load/env.js b/lib/load/env.js index acb40f4b1d..41d45fcd68 100644 --- a/lib/load/env.js +++ b/lib/load/env.js @@ -1,59 +1,60 @@ -const fs = require('fs-extra'); -const path = require('path'); - -module.exports = function loadEnv({siteDir, siteConfig}) { - // Translation - const translation = { - enabled: false, - enabledLanguages: [], - defaultLanguage: {} - }; - - const languagesFile = path.join(siteDir, 'languages.js'); - if (fs.existsSync(languagesFile)) { - const languages = require(languagesFile); - - /* Enabled languages */ - const enabledLanguages = languages.filter(lang => lang.enabled); - if (!enabledLanguages || enabledLanguages.length === 0) { - throw new Error(`Please at least enable one language in 'languages.js'`); - } - translation.enabledLanguages = enabledLanguages; - - /* Default Language */ - const {defaultLanguage: defaultLanguageTag} = siteConfig; - const defaultLanguage = enabledLanguages.find( - lang => lang.tag === defaultLanguageTag - ); - if (!defaultLanguage) { - throw new Error( - `Please set a default language in 'siteConfig.js' which is enabled in 'languages.js'` - ); - } - translation.defaultLanguage = defaultLanguage; - - translation.enabled = true; - } - - // Versioning - const versioning = { - enabled: false, - latestVersion: null, - defaultVersion: null, - versions: [] - }; - - const versionsJSONFile = path.join(siteDir, 'versions.json'); - if (fs.existsSync(versionsJSONFile)) { - versioning.enabled = true; - versioning.versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8')); - versioning.latestVersion = versioning.versions[0]; - const {defaultVersionShown} = siteConfig; - versioning.defaultVersion = defaultVersionShown || versioning.latestVersion; - } - - return { - translation, - versioning - }; -}; +const fs = require('fs-extra'); +const path = require('path'); +const {idx} = require('./utils'); + +module.exports = function loadEnv({siteDir, siteConfig}) { + // Translation + const translation = { + enabled: false, + enabledLanguages: [], + defaultLanguage: {} + }; + + const languagesFile = path.join(siteDir, 'languages.js'); + if (fs.existsSync(languagesFile)) { + const languages = require(languagesFile); // eslint-disable-line + + /* Enabled languages */ + const enabledLanguages = languages.filter(lang => lang.enabled); + if (!enabledLanguages || enabledLanguages.length === 0) { + throw new Error(`Please at least enable one language in 'languages.js'`); + } + translation.enabledLanguages = enabledLanguages; + + /* Default Language */ + const {defaultLanguage: defaultLanguageTag} = siteConfig; + const defaultLanguage = enabledLanguages.find( + lang => lang.tag === defaultLanguageTag + ); + if (!defaultLanguage) { + throw new Error( + `Please set a default language in 'siteConfig.js' which is enabled in 'languages.js'` + ); + } + translation.defaultLanguage = defaultLanguage; + + translation.enabled = true; + } + + // Versioning + const versioning = { + enabled: false, + latestVersion: null, + defaultVersion: null, + versions: [] + }; + + const versionsJSONFile = path.join(siteDir, 'versions.json'); + if (fs.existsSync(versionsJSONFile)) { + versioning.enabled = true; + versioning.versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8')); + versioning.latestVersion = idx(versioning, ['versions', 0]); + const {defaultVersionShown} = siteConfig; + versioning.defaultVersion = defaultVersionShown || versioning.latestVersion; + } + + return { + translation, + versioning + }; +}; diff --git a/lib/load/index.js b/lib/load/index.js index 7cebbc0271..6e2d381ac7 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -8,10 +8,10 @@ const {generate} = require('./utils'); const genRoutesConfig = require('./routes'); module.exports = async function load(siteDir) { - // siteConfig + // @tested - siteConfig const siteConfig = loadConfig(siteDir); - // env + // @tested - env const env = loadEnv({siteDir, siteConfig}); // docs @@ -20,7 +20,7 @@ module.exports = async function load(siteDir) { '..', siteConfig.customDocsPath || 'docs' ); - const docsData = await loadDocs(docsDir); + const docsData = await loadDocs({siteDir, docsDir, env}); await generate( 'docsData.js', `export default ${JSON.stringify(docsData, null, 2)};` diff --git a/lib/load/routes.js b/lib/load/routes.js index 282446327a..42193e0631 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,15 +1,38 @@ -async function genRoutesConfig({docsData = [], pagesData = []}) { - function genDocsRoute({path: docsPath, source}) { +const {idx} = require('./utils'); + +async function genRoutesConfig({ + docsData = {}, + pagesData = [], + env, + siteConfig +}) { + function genDocsRoute(metadata) { + const {permalink, source, version, language} = metadata; + const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); + let importPath = `@docs/${source}`; + if (language && language !== defaultLanguage.tag) { + importPath = `@translated_docs/${source}`; + } else if (version && version !== 'next') { + importPath = `@versioned_docs/${source}`; + } + + const {baseUrl} = siteConfig; + const docsPath = `${baseUrl}${permalink}`; + return ` { path: ${JSON.stringify(docsPath)}, exact: true, component: Loadable({ - loader: () => import('@docs/${source}'), + loader: () => import(${JSON.stringify(importPath)}), loading: Loading, render(loaded, props) { let Content = loaded.default; - return ; + return ( + + + + ); } }) }`; @@ -33,13 +56,17 @@ async function genRoutesConfig({docsData = [], pagesData = []}) { component: NotFound }`; + const docsRoutes = Object.values(docsData) + .map(genDocsRoute) + .join(','); + return ( `import React from 'react';\n` + `import Loadable from 'react-loadable';\n` + `import Loading from '@theme/Loading';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + - `const routes = [${docsData.map(genDocsRoute).join(',')},${pagesData + `const routes = [${docsRoutes},${pagesData .map(genPagesRoute) .join(',')}${notFoundRoute}\n];\n` + `export default routes;\n` diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index 910684ead6..e74b8586b3 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -6,13 +6,11 @@ import Layout from '@theme/Layout'; // eslint-disable-line export default class Docs extends React.Component { render() { - const {route, docsData, siteConfig} = this.props; - const currentDoc = docsData.find(data => data.path === route.path); - + const {route, siteConfig, metadata} = this.props; return ( - {(currentDoc && currentDoc.title) || siteConfig.title} + {(metadata && metadata.title) || siteConfig.title}

    {this.props.children}
    diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index fdd755a713..10f908e0ea 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -1,12 +1,16 @@ import React from 'react'; import {Link} from 'react-router-dom'; +import siteConfig from '@site/siteConfig'; import styles from './styles.css'; /* eslint-disable react/prefer-stateless-function */ export default class Layout extends React.Component { render() { - const {children, pagesData, docsData, location} = this.props; - const routeLinks = [...pagesData, ...docsData].map( + const {children, pagesData, docsData = {}, location} = this.props; + const docsLinks = Object.values(docsData).map(data => ({ + path: `${siteConfig.baseUrl}${data.permalink}` + })); + const routeLinks = [...pagesData, ...docsLinks].map( data => data.path !== location.pathname && (
  • diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 2e3b496294..9a52de54af 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -32,6 +32,8 @@ module.exports = function createBaseConfig(props, isServer) { .set('symlinks', true) .alias.set('@theme', themePath) .set('@site', siteDir) + .set('@versioned_docs', path.resolve(siteDir, 'versioned_docs')) + .set('@translated_docs', path.resolve(siteDir, 'translated_docs')) .set('@docs', docsDir) .set('@pages', pagesDir) .set('@build', outDir) diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index c11f3f671f..97bafff5dd 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -5,10 +5,11 @@ module.exports = function(fileString) { const options = getOptions(this); const {body} = fm(fileString); - const content = JSON.stringify(body); - // TODO replace all the markdown linking to correct url depends on whether it's versioned/translated/normal docs - // e.g: [test](test.md) become [test](/docs/test) + /* + TODO replace all the markdown linking to correct url depends on whether it's versioned/translated/normal docs + e.g: [test](test.md) become [test](/docs/test) + */ const siteConfig = JSON.stringify(options.siteConfig); return ( diff --git a/test/load/__snapshots__/pages.test.js.snap b/test/load/__snapshots__/pages.test.js.snap deleted file mode 100644 index daa058daba..0000000000 --- a/test/load/__snapshots__/pages.test.js.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loadPages valid pages 1`] = ` -Array [ - Object { - "path": "/foo", - "source": "foo.js", - }, - Object { - "path": "/", - "source": "index.js", - }, - Object { - "path": "/foo/", - "source": "foo/index.js", - }, - Object { - "path": "/bar/baz", - "source": "bar/baz.js", - }, -] -`; diff --git a/test/load/__snapshots__/routes.test.js.snap b/test/load/__snapshots__/routes.test.js.snap deleted file mode 100644 index c9c8cbad84..0000000000 --- a/test/load/__snapshots__/routes.test.js.snap +++ /dev/null @@ -1,201 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`genRoutesConfig website with no docs/pages 1`] = ` -"import React from 'react'; -import Loadable from 'react-loadable'; -import Loading from '@theme/Loading'; -import Docs from '@theme/Docs'; -import NotFound from '@theme/NotFound'; -const routes = [,, - { - path: '*', - component: NotFound - } -]; -export default routes; -" -`; - -exports[`genRoutesConfig website with only docs 1`] = ` -"import React from 'react'; -import Loadable from 'react-loadable'; -import Loading from '@theme/Loading'; -import Docs from '@theme/Docs'; -import NotFound from '@theme/NotFound'; -const routes = [ - { - path: \\"/hello\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/hello.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - }, - { - path: \\"/foo/baz\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/foo/baz.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - }, - { - path: \\"/foo/bar\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/foo/bar.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - },, - { - path: '*', - component: NotFound - } -]; -export default routes; -" -`; - -exports[`genRoutesConfig website with only pages 1`] = ` -"import React from 'react'; -import Loadable from 'react-loadable'; -import Loading from '@theme/Loading'; -import Docs from '@theme/Docs'; -import NotFound from '@theme/NotFound'; -const routes = [, - { - path: \\"/foo\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/foo.js'), - loading: Loading - }) - }, - { - path: \\"/\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/index.js'), - loading: Loading - }) - }, - { - path: \\"/bar/baz\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/bar/baz.js'), - loading: Loading - }) - }, - { - path: \\"/foo/\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/foo/index.js'), - loading: Loading - }) - }, - { - path: '*', - component: NotFound - } -]; -export default routes; -" -`; - -exports[`genRoutesConfig website with pages and docs 1`] = ` -"import React from 'react'; -import Loadable from 'react-loadable'; -import Loading from '@theme/Loading'; -import Docs from '@theme/Docs'; -import NotFound from '@theme/NotFound'; -const routes = [ - { - path: \\"/hello\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/hello.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - }, - { - path: \\"/foo/bar\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/foo/bar.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - }, - { - path: \\"/foo/baz\\", - exact: true, - component: Loadable({ - loader: () => import('@docs/foo/baz.md'), - loading: Loading, - render(loaded, props) { - let Content = loaded.default; - return ; - } - }) - }, - { - path: \\"/\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/index.js'), - loading: Loading - }) - }, - { - path: \\"/foo\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/foo.js'), - loading: Loading - }) - }, - { - path: \\"/foo/\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/foo/index.js'), - loading: Loading - }) - }, - { - path: \\"/bar/baz\\", - exact: true, - component: Loadable({ - loader: () => import('@pages/bar/baz.js'), - loading: Loading - }) - }, - { - path: '*', - component: NotFound - } -]; -export default routes; -" -`; diff --git a/test/load/docs.test.js b/test/load/docs.test.js deleted file mode 100644 index 01588e12f9..0000000000 --- a/test/load/docs.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import loadDocs from '@lib/load/docs'; -import path from 'path'; - -describe('loadDocs', () => { - test('simple docs', async () => { - const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); - const docsData = await loadDocs(docsDir); - expect(docsData).toMatchSnapshot(); - expect(docsData).not.toBeNull(); - }); - - test('no docs', async () => { - const nonExistingDocsDir = path.join( - __dirname, - '__fixtures__', - 'nonExistingDocs' - ); - const docsData = await loadDocs(nonExistingDocsDir); - expect(docsData).toEqual([]); - }); -}); diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/test/load/docs/__snapshots__/index.test.js.snap new file mode 100644 index 0000000000..2ec8c5e0ce --- /dev/null +++ b/test/load/docs/__snapshots__/index.test.js.snap @@ -0,0 +1,593 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadDocs simple website 1`] = ` +Object { + "baseUrl": "/", + "docsData": Object { + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": undefined, + }, + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": undefined, + }, + "hello": Object { + "id": "hello", + "language": undefined, + "localized_id": "hello", + "permalink": "docs/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": undefined, + }, + }, + "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", + "env": Object { + "translation": Object { + "defaultLanguage": Object {}, + "enabled": false, + "enabledLanguages": Array [], + }, + "versioning": Object { + "defaultVersion": null, + "enabled": false, + "latestVersion": null, + "versions": Array [], + }, + }, + "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site/build", + "pagesData": Array [ + Object { + "path": "/", + "source": "index.js", + }, + Object { + "path": "/hello/world", + "source": "hello/world.js", + }, + ], + "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site/pages", + "siteConfig": Object { + "baseUrl": "/", + "organizationName": "endiliey", + "projectName": "hello", + "tagline": "Hello World", + "title": "Hello", + }, + "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site", + "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", +} +`; + +exports[`loadDocs translated website 1`] = ` +Object { + "baseUrl": "/", + "docsData": Object { + "en-hello": Object { + "id": "en-hello", + "language": "en", + "localized_id": "en-hello", + "permalink": "docs/en/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": undefined, + }, + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": undefined, + }, + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": undefined, + }, + "ko-docs/foo/bar": Object { + "id": "ko-docs/foo/bar", + "language": "ko", + "localized_id": "ko-docs/foo/bar", + "permalink": "docs/ko/docs/foo/bar", + "source": "ko/docs/foo/bar.md", + "title": "Bar", + "version": undefined, + }, + "ko-docs/foo/baz": Object { + "id": "ko-docs/foo/baz", + "language": "ko", + "localized_id": "ko-docs/foo/baz", + "permalink": "docs/ko/docs/foo/baz", + "source": "ko/docs/foo/baz.md", + "title": "baz", + "version": undefined, + }, + "ko-docs/hello": Object { + "id": "ko-docs/hello", + "language": "ko", + "localized_id": "ko-docs/hello", + "permalink": "docs/ko/docs/hello", + "source": "ko/docs/hello.md", + "title": "Hello, World !", + "version": undefined, + }, + }, + "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", + "env": Object { + "translation": Object { + "defaultLanguage": Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + "enabled": true, + "enabledLanguages": Array [ + Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + Object { + "enabled": true, + "name": "한국어", + "tag": "ko", + }, + ], + }, + "versioning": Object { + "defaultVersion": null, + "enabled": false, + "latestVersion": null, + "versions": Array [], + }, + }, + "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site/build", + "pagesData": Array [ + Object { + "path": "/", + "source": "index.js", + }, + Object { + "path": "/hello/world", + "source": "hello/world.js", + }, + ], + "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site/pages", + "siteConfig": Object { + "baseUrl": "/", + "defaultLanguage": "en", + "organizationName": "endiliey", + "projectName": "hello", + "tagline": "Hello World", + "title": "Hello", + }, + "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site", + "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", +} +`; + +exports[`loadDocs versioned & translated website 1`] = ` +Object { + "baseUrl": "/", + "docsData": Object { + "en-hello": Object { + "id": "en-hello", + "language": "en", + "localized_id": "en-hello", + "permalink": "docs/en/next/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": "next", + }, + "foo/bar": Object { + "category": "Test", + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "next": "foo/baz", + "next_id": "foo/baz", + "next_title": "baz", + "permalink": "docs/next/foo/bar", + "sidebar": "docs", + "source": "foo/bar.md", + "title": "Bar", + "version": "next", + }, + "foo/baz": Object { + "category": "Test", + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "next": "hello", + "next_id": "hello", + "next_title": "Next", + "permalink": "docs/next/foo/baz", + "previous": "foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", + "source": "foo/baz.md", + "title": "baz", + "version": "next", + }, + "ko-version-1.0.0-version-1.0.0/foo/bar": Object { + "id": "ko-version-1.0.0-version-1.0.0/foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/foo/bar", + "permalink": "docs/ko/1.0.0/version-1.0.0/foo/bar", + "source": "ko/version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "ko-version-1.0.0-version-1.0.0/foo/baz": Object { + "id": "ko-version-1.0.0-version-1.0.0/foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/foo/baz", + "permalink": "docs/ko/1.0.0/version-1.0.0/foo/baz", + "source": "ko/version-1.0.0/foo/baz.md", + "title": "baz", + "version": "1.0.0", + }, + "ko-version-1.0.0-version-1.0.0/hello": Object { + "id": "ko-version-1.0.0-version-1.0.0/hello", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/hello", + "permalink": "docs/ko/1.0.0/version-1.0.0/hello", + "source": "ko/version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "ko-version-1.0.1-version-1.0.1/foo/bar": Object { + "id": "ko-version-1.0.1-version-1.0.1/foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/foo/bar", + "permalink": "docs/ko/version-1.0.1/foo/bar", + "source": "ko/version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "ko-version-1.0.1-version-1.0.1/foo/baz": Object { + "id": "ko-version-1.0.1-version-1.0.1/foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/foo/baz", + "permalink": "docs/ko/version-1.0.1/foo/baz", + "source": "ko/version-1.0.1/foo/baz.md", + "title": "baz", + "version": "1.0.1", + }, + "ko-version-1.0.1-version-1.0.1/hello": Object { + "id": "ko-version-1.0.1-version-1.0.1/hello", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/hello", + "permalink": "docs/ko/version-1.0.1/hello", + "source": "ko/version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", + }, + "version-1.0.0-foo/bar": Object { + "category": "Test", + "id": "version-1.0.0-foo/bar", + "language": undefined, + "localized_id": "version-1.0.0-foo/bar", + "next": "version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "Baz", + "permalink": "docs/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "version-1.0.0-foo/baz": Object { + "category": "Test", + "id": "version-1.0.0-foo/baz", + "language": undefined, + "localized_id": "version-1.0.0-foo/baz", + "next": "version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", + "permalink": "docs/1.0.0/foo/baz", + "previous": "version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/baz.md", + "title": "Baz", + "version": "1.0.0", + }, + "version-1.0.0-hello": Object { + "category": "Guides", + "id": "version-1.0.0-hello", + "language": undefined, + "localized_id": "version-1.0.0-hello", + "permalink": "docs/1.0.0/hello", + "previous": "version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "version-1.0.1-foo/bar": Object { + "category": "Test", + "id": "version-1.0.1-foo/bar", + "language": undefined, + "localized_id": "version-1.0.1-foo/bar", + "next": "version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "Baz", + "permalink": "docs/foo/bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "version-1.0.1-foo/baz": Object { + "category": "Test", + "id": "version-1.0.1-foo/baz", + "language": undefined, + "localized_id": "version-1.0.1-foo/baz", + "next": "version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", + "permalink": "docs/foo/baz", + "previous": "version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/baz.md", + "title": "Baz", + "version": "1.0.1", + }, + "version-1.0.1-hello": Object { + "category": "Guides", + "id": "version-1.0.1-hello", + "language": undefined, + "localized_id": "version-1.0.1-hello", + "permalink": "docs/hello", + "previous": "version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", + }, + }, + "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", + "env": Object { + "translation": Object { + "defaultLanguage": Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + "enabled": true, + "enabledLanguages": Array [ + Object { + "enabled": true, + "name": "English", + "tag": "en", + }, + Object { + "enabled": true, + "name": "한국어", + "tag": "ko", + }, + ], + }, + "versioning": Object { + "defaultVersion": "1.0.1", + "enabled": true, + "latestVersion": "1.0.1", + "versions": Array [ + "1.0.1", + "1.0.0", + ], + }, + }, + "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site/build", + "pagesData": Array [ + Object { + "path": "/", + "source": "index.js", + }, + Object { + "path": "/hello/world", + "source": "hello/world.js", + }, + ], + "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site/pages", + "siteConfig": Object { + "baseUrl": "/", + "defaultLanguage": "en", + "organizationName": "endiliey", + "projectName": "hello", + "tagline": "Hello World", + "title": "Hello", + }, + "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site", + "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", +} +`; + +exports[`loadDocs versioned website 1`] = ` +Object { + "baseUrl": "/", + "docsData": Object { + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/next/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": "next", + }, + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/next/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": "next", + }, + "hello": Object { + "id": "hello", + "language": undefined, + "localized_id": "hello", + "permalink": "docs/next/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": "next", + }, + "version-1.0.0-foo/bar": Object { + "category": "Test", + "id": "version-1.0.0-foo/bar", + "language": undefined, + "localized_id": "version-1.0.0-foo/bar", + "next": "version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "Baz", + "permalink": "docs/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "version-1.0.0-foo/baz": Object { + "category": "Test", + "id": "version-1.0.0-foo/baz", + "language": undefined, + "localized_id": "version-1.0.0-foo/baz", + "next": "version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", + "permalink": "docs/1.0.0/foo/baz", + "previous": "version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/baz.md", + "title": "Baz", + "version": "1.0.0", + }, + "version-1.0.0-hello": Object { + "category": "Guides", + "id": "version-1.0.0-hello", + "language": undefined, + "localized_id": "version-1.0.0-hello", + "permalink": "docs/1.0.0/hello", + "previous": "version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "version-1.0.1-foo/bar": Object { + "category": "Test", + "id": "version-1.0.1-foo/bar", + "language": undefined, + "localized_id": "version-1.0.1-foo/bar", + "next": "version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "Baz", + "permalink": "docs/foo/bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "version-1.0.1-foo/baz": Object { + "category": "Test", + "id": "version-1.0.1-foo/baz", + "language": undefined, + "localized_id": "version-1.0.1-foo/baz", + "next": "version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", + "permalink": "docs/foo/baz", + "previous": "version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/baz.md", + "title": "Baz", + "version": "1.0.1", + }, + "version-1.0.1-hello": Object { + "category": "Guides", + "id": "version-1.0.1-hello", + "language": undefined, + "localized_id": "version-1.0.1-hello", + "permalink": "docs/hello", + "previous": "version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", + }, + }, + "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", + "env": Object { + "translation": Object { + "defaultLanguage": Object {}, + "enabled": false, + "enabledLanguages": Array [], + }, + "versioning": Object { + "defaultVersion": "1.0.1", + "enabled": true, + "latestVersion": "1.0.1", + "versions": Array [ + "1.0.1", + "1.0.0", + ], + }, + }, + "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site/build", + "pagesData": Array [ + Object { + "path": "/", + "source": "index.js", + }, + Object { + "path": "/hello/world", + "source": "hello/world.js", + }, + ], + "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site/pages", + "siteConfig": Object { + "baseUrl": "/", + "organizationName": "endiliey", + "projectName": "hello", + "tagline": "Hello World", + "title": "Hello", + }, + "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site", + "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", +} +`; diff --git a/test/load/docs/index.test.js b/test/load/docs/index.test.js new file mode 100644 index 0000000000..af1a083f1c --- /dev/null +++ b/test/load/docs/index.test.js @@ -0,0 +1,23 @@ +import loadSetup from '../../loadSetup'; + +describe('loadDocs', () => { + test('simple website', async () => { + const props = await loadSetup('simple'); + expect(props).toMatchSnapshot(); + }); + + test('versioned website', async () => { + const props = await loadSetup('versioned'); + expect(props).toMatchSnapshot(); + }); + + test('versioned & translated website', async () => { + const props = await loadSetup('transversioned'); + expect(props).toMatchSnapshot(); + }); + + test('translated website', async () => { + const props = await loadSetup('translated'); + expect(props).toMatchSnapshot(); + }); +}); diff --git a/test/load/docs/order.test.js b/test/load/docs/order.test.js index ef4d0f2b66..981c2a00cf 100644 --- a/test/load/docs/order.test.js +++ b/test/load/docs/order.test.js @@ -1,35 +1,35 @@ -import createOrder from '@lib/load/docs/order'; - -describe('createOrder', () => { - test('should populate docs index from multiple sidebars', () => { - const result = createOrder({ - docs: { - Category1: ['doc1', 'doc2'], - Category2: ['doc3', 'doc4'] - }, - otherDocs: { - Category1: ['doc5'] - } - }); - expect(result).toMatchSnapshot(); - }); - - test('should resolve docs from older versions', () => { - const result = createOrder({ - docs: { - Category1: ['doc1'] - }, - 'version-1.2.3-docs': { - Category1: ['version-1.2.3-doc2'], - Category2: ['version-1.2.3-doc1'] - } - }); - expect(result).toMatchSnapshot(); - }); - - test('edge cases', () => { - expect(createOrder({})).toEqual({}); - expect(createOrder(null)).toEqual({}); - expect(createOrder(undefined)).toEqual({}); - }); -}); +import createOrder from '@lib/load/docs/order'; + +describe('createOrder', () => { + test('should populate docs index from multiple sidebars', () => { + const result = createOrder({ + docs: { + Category1: ['doc1', 'doc2'], + Category2: ['doc3', 'doc4'] + }, + otherDocs: { + Category1: ['doc5'] + } + }); + expect(result).toMatchSnapshot(); + }); + + test('should resolve docs from older versions', () => { + const result = createOrder({ + docs: { + Category1: ['doc1'] + }, + 'version-1.2.3-docs': { + Category1: ['version-1.2.3-doc2'], + Category2: ['version-1.2.3-doc1'] + } + }); + expect(result).toMatchSnapshot(); + }); + + test('edge cases', () => { + expect(createOrder({})).toEqual({}); + expect(createOrder(null)).toEqual({}); + expect(createOrder(undefined)).toEqual({}); + }); +}); diff --git a/test/load/docs/sidebars.test.js b/test/load/docs/sidebars.test.js index d5cb1411b8..6aebf8e966 100644 --- a/test/load/docs/sidebars.test.js +++ b/test/load/docs/sidebars.test.js @@ -1,46 +1,46 @@ -import path from 'path'; -import loadSidebars from '@lib/load/docs/sidebars'; - -describe('loadSidebars', () => { - const fixtures = path.join(__dirname, '..', '__fixtures__'); - test('normal site with sidebars', () => { - const env = {}; - const siteDir = path.join(fixtures, 'simple-site'); - const result = loadSidebars({siteDir, env}); - expect(result).toMatchSnapshot(); - }); - - test('site without sidebars', () => { - const env = {}; - const siteDir = path.join(fixtures, 'bad-site'); - const result = loadSidebars({siteDir, env}); - expect(result).toMatchSnapshot(); - }); - - test('site with sidebars & versioned sidebars', () => { - const env = { - versioning: { - enabled: true, - versions: ['1.0.1', '1.0.0'] - } - }; - const siteDir = path.join(fixtures, 'versioned-site'); - const result = loadSidebars({siteDir, env}); - expect(result).toMatchSnapshot(); - }); - - test('site with missing versioned sidebars', () => { - const env = { - versioning: { - enabled: true, - versions: ['2.0.0'] - } - }; - const siteDir = path.join(fixtures, 'versioned-site'); - expect(() => { - loadSidebars({siteDir, env}); - }).toThrowErrorMatchingInlineSnapshot( - `"Failed to load versioned_sidebars/version-2.0.0-sidebars.json. It does not exist."` - ); - }); -}); +import path from 'path'; +import loadSidebars from '@lib/load/docs/sidebars'; + +describe('loadSidebars', () => { + const fixtures = path.join(__dirname, '..', '__fixtures__'); + test('normal site with sidebars', () => { + const env = {}; + const siteDir = path.join(fixtures, 'simple-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site without sidebars', () => { + const env = {}; + const siteDir = path.join(fixtures, 'bad-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site with sidebars & versioned sidebars', () => { + const env = { + versioning: { + enabled: true, + versions: ['1.0.1', '1.0.0'] + } + }; + const siteDir = path.join(fixtures, 'versioned-site'); + const result = loadSidebars({siteDir, env}); + expect(result).toMatchSnapshot(); + }); + + test('site with missing versioned sidebars', () => { + const env = { + versioning: { + enabled: true, + versions: ['2.0.0'] + } + }; + const siteDir = path.join(fixtures, 'versioned-site'); + expect(() => { + loadSidebars({siteDir, env}); + }).toThrowErrorMatchingInlineSnapshot( + `"Failed to load versioned_sidebars/version-2.0.0-sidebars.json. It does not exist."` + ); + }); +}); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index 7a76e76a82..06e80bbcab 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -5,7 +5,24 @@ describe('loadPages', () => { test('valid pages', async () => { const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); const pagesData = await loadPages(pagesDir); - expect(pagesData).toMatchSnapshot(); + expect(pagesData).toEqual([ + { + path: '/', + source: 'index.js' + }, + { + path: '/foo', + source: 'foo.js' + }, + { + path: '/foo/', + source: 'foo/index.js' + }, + { + path: '/bar/baz', + source: 'bar/baz.js' + } + ]); expect(pagesData).not.toBeNull(); }); diff --git a/test/load/routes.test.js b/test/load/routes.test.js index 7022c420a4..28ba6c19df 100644 --- a/test/load/routes.test.js +++ b/test/load/routes.test.js @@ -1,39 +1,24 @@ import genRoutesConfig from '@lib/load/routes'; -import loadDocs from '@lib/load/docs'; -import loadPages from '@lib/load/pages'; -import path from 'path'; +import loadSetup from '../loadSetup'; describe('genRoutesConfig', () => { - const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - const docsDir = path.join(__dirname, '__fixtures__', 'simple-docs'); - - test('website with pages and docs', async () => { - const props = { - docsData: await loadDocs(docsDir), - pagesData: await loadPages(pagesDir) - }; - const routes = await genRoutesConfig(props); - expect(routes).toMatchSnapshot(); + test('simple website', async () => { + const props = await loadSetup('simple'); + await genRoutesConfig(props); }); - test('website with only pages', async () => { - const props = { - pagesData: await loadPages(pagesDir) - }; - const routes = await genRoutesConfig(props); - expect(routes).toMatchSnapshot(); + test('versioned website', async () => { + const props = await loadSetup('versioned'); + await genRoutesConfig(props); }); - test('website with only docs', async () => { - const props = { - docsData: await loadDocs(docsDir) - }; - const routes = await genRoutesConfig(props); - expect(routes).toMatchSnapshot(); + test('versioned & translated website', async () => { + const props = await loadSetup('transversioned'); + await genRoutesConfig(props); }); - test('website with no docs/pages', async () => { - const routes = await genRoutesConfig({}); - expect(routes).toMatchSnapshot(); + test('translated website', async () => { + const props = await loadSetup('translated'); + await genRoutesConfig(props); }); }); From 0cef519e7fdc8fa2ff8b9026371e69359509811b Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 21:51:18 +0800 Subject: [PATCH 110/135] test: fix inconsistent test --- .../docs/__snapshots__/index.test.js.snap | 930 +++++++----------- test/load/docs/index.test.js | 17 +- test/load/pages.test.js | 11 +- 3 files changed, 389 insertions(+), 569 deletions(-) diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/test/load/docs/__snapshots__/index.test.js.snap index 2ec8c5e0ce..76faa67270 100644 --- a/test/load/docs/__snapshots__/index.test.js.snap +++ b/test/load/docs/__snapshots__/index.test.js.snap @@ -2,592 +2,402 @@ exports[`loadDocs simple website 1`] = ` Object { - "baseUrl": "/", - "docsData": Object { - "foo/bar": Object { - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "permalink": "docs/foo/bar", - "source": "foo/bar.md", - "title": "Bar", - "version": undefined, - }, - "foo/baz": Object { - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "permalink": "docs/foo/baz", - "source": "foo/baz.md", - "title": "baz", - "version": undefined, - }, - "hello": Object { - "id": "hello", - "language": undefined, - "localized_id": "hello", - "permalink": "docs/hello", - "source": "hello.md", - "title": "Hello, World !", - "version": undefined, - }, + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": undefined, }, - "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", - "env": Object { - "translation": Object { - "defaultLanguage": Object {}, - "enabled": false, - "enabledLanguages": Array [], - }, - "versioning": Object { - "defaultVersion": null, - "enabled": false, - "latestVersion": null, - "versions": Array [], - }, + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": undefined, }, - "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site/build", - "pagesData": Array [ - Object { - "path": "/", - "source": "index.js", - }, - Object { - "path": "/hello/world", - "source": "hello/world.js", - }, - ], - "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site/pages", - "siteConfig": Object { - "baseUrl": "/", - "organizationName": "endiliey", - "projectName": "hello", - "tagline": "Hello World", - "title": "Hello", + "hello": Object { + "id": "hello", + "language": undefined, + "localized_id": "hello", + "permalink": "docs/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": undefined, }, - "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/simple-site", - "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", } `; exports[`loadDocs translated website 1`] = ` Object { - "baseUrl": "/", - "docsData": Object { - "en-hello": Object { - "id": "en-hello", - "language": "en", - "localized_id": "en-hello", - "permalink": "docs/en/hello", - "source": "hello.md", - "title": "Hello, World !", - "version": undefined, - }, - "foo/bar": Object { - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "permalink": "docs/foo/bar", - "source": "foo/bar.md", - "title": "Bar", - "version": undefined, - }, - "foo/baz": Object { - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "permalink": "docs/foo/baz", - "source": "foo/baz.md", - "title": "baz", - "version": undefined, - }, - "ko-docs/foo/bar": Object { - "id": "ko-docs/foo/bar", - "language": "ko", - "localized_id": "ko-docs/foo/bar", - "permalink": "docs/ko/docs/foo/bar", - "source": "ko/docs/foo/bar.md", - "title": "Bar", - "version": undefined, - }, - "ko-docs/foo/baz": Object { - "id": "ko-docs/foo/baz", - "language": "ko", - "localized_id": "ko-docs/foo/baz", - "permalink": "docs/ko/docs/foo/baz", - "source": "ko/docs/foo/baz.md", - "title": "baz", - "version": undefined, - }, - "ko-docs/hello": Object { - "id": "ko-docs/hello", - "language": "ko", - "localized_id": "ko-docs/hello", - "permalink": "docs/ko/docs/hello", - "source": "ko/docs/hello.md", - "title": "Hello, World !", - "version": undefined, - }, + "en-hello": Object { + "id": "en-hello", + "language": "en", + "localized_id": "en-hello", + "permalink": "docs/en/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": undefined, }, - "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", - "env": Object { - "translation": Object { - "defaultLanguage": Object { - "enabled": true, - "name": "English", - "tag": "en", - }, - "enabled": true, - "enabledLanguages": Array [ - Object { - "enabled": true, - "name": "English", - "tag": "en", - }, - Object { - "enabled": true, - "name": "한국어", - "tag": "ko", - }, - ], - }, - "versioning": Object { - "defaultVersion": null, - "enabled": false, - "latestVersion": null, - "versions": Array [], - }, + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": undefined, }, - "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site/build", - "pagesData": Array [ - Object { - "path": "/", - "source": "index.js", - }, - Object { - "path": "/hello/world", - "source": "hello/world.js", - }, - ], - "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site/pages", - "siteConfig": Object { - "baseUrl": "/", - "defaultLanguage": "en", - "organizationName": "endiliey", - "projectName": "hello", - "tagline": "Hello World", - "title": "Hello", + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": undefined, + }, + "ko-docs/foo/bar": Object { + "id": "ko-docs/foo/bar", + "language": "ko", + "localized_id": "ko-docs/foo/bar", + "permalink": "docs/ko/docs/foo/bar", + "source": "ko/docs/foo/bar.md", + "title": "Bar", + "version": undefined, + }, + "ko-docs/foo/baz": Object { + "id": "ko-docs/foo/baz", + "language": "ko", + "localized_id": "ko-docs/foo/baz", + "permalink": "docs/ko/docs/foo/baz", + "source": "ko/docs/foo/baz.md", + "title": "baz", + "version": undefined, + }, + "ko-docs/hello": Object { + "id": "ko-docs/hello", + "language": "ko", + "localized_id": "ko-docs/hello", + "permalink": "docs/ko/docs/hello", + "source": "ko/docs/hello.md", + "title": "Hello, World !", + "version": undefined, }, - "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/translated-site", - "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", } `; exports[`loadDocs versioned & translated website 1`] = ` Object { - "baseUrl": "/", - "docsData": Object { - "en-hello": Object { - "id": "en-hello", - "language": "en", - "localized_id": "en-hello", - "permalink": "docs/en/next/hello", - "source": "hello.md", - "title": "Hello, World !", - "version": "next", - }, - "foo/bar": Object { - "category": "Test", - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "next": "foo/baz", - "next_id": "foo/baz", - "next_title": "baz", - "permalink": "docs/next/foo/bar", - "sidebar": "docs", - "source": "foo/bar.md", - "title": "Bar", - "version": "next", - }, - "foo/baz": Object { - "category": "Test", - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "next": "hello", - "next_id": "hello", - "next_title": "Next", - "permalink": "docs/next/foo/baz", - "previous": "foo/bar", - "previous_id": "foo/bar", - "previous_title": "Bar", - "sidebar": "docs", - "source": "foo/baz.md", - "title": "baz", - "version": "next", - }, - "ko-version-1.0.0-version-1.0.0/foo/bar": Object { - "id": "ko-version-1.0.0-version-1.0.0/foo/bar", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/foo/bar", - "permalink": "docs/ko/1.0.0/version-1.0.0/foo/bar", - "source": "ko/version-1.0.0/foo/bar.md", - "title": "Bar", - "version": "1.0.0", - }, - "ko-version-1.0.0-version-1.0.0/foo/baz": Object { - "id": "ko-version-1.0.0-version-1.0.0/foo/baz", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/foo/baz", - "permalink": "docs/ko/1.0.0/version-1.0.0/foo/baz", - "source": "ko/version-1.0.0/foo/baz.md", - "title": "baz", - "version": "1.0.0", - }, - "ko-version-1.0.0-version-1.0.0/hello": Object { - "id": "ko-version-1.0.0-version-1.0.0/hello", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/hello", - "permalink": "docs/ko/1.0.0/version-1.0.0/hello", - "source": "ko/version-1.0.0/hello.md", - "title": "Hello, World !", - "version": "1.0.0", - }, - "ko-version-1.0.1-version-1.0.1/foo/bar": Object { - "id": "ko-version-1.0.1-version-1.0.1/foo/bar", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/foo/bar", - "permalink": "docs/ko/version-1.0.1/foo/bar", - "source": "ko/version-1.0.1/foo/bar.md", - "title": "Bar", - "version": "1.0.1", - }, - "ko-version-1.0.1-version-1.0.1/foo/baz": Object { - "id": "ko-version-1.0.1-version-1.0.1/foo/baz", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/foo/baz", - "permalink": "docs/ko/version-1.0.1/foo/baz", - "source": "ko/version-1.0.1/foo/baz.md", - "title": "baz", - "version": "1.0.1", - }, - "ko-version-1.0.1-version-1.0.1/hello": Object { - "id": "ko-version-1.0.1-version-1.0.1/hello", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/hello", - "permalink": "docs/ko/version-1.0.1/hello", - "source": "ko/version-1.0.1/hello.md", - "title": "Hello, World !", - "version": "1.0.1", - }, - "version-1.0.0-foo/bar": Object { - "category": "Test", - "id": "version-1.0.0-foo/bar", - "language": undefined, - "localized_id": "version-1.0.0-foo/bar", - "next": "version-1.0.0-foo/baz", - "next_id": "version-1.0.0-foo/baz", - "next_title": "Baz", - "permalink": "docs/1.0.0/foo/bar", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/bar.md", - "title": "Bar", - "version": "1.0.0", - }, - "version-1.0.0-foo/baz": Object { - "category": "Test", - "id": "version-1.0.0-foo/baz", - "language": undefined, - "localized_id": "version-1.0.0-foo/baz", - "next": "version-1.0.0-hello", - "next_id": "version-1.0.0-hello", - "next_title": "Hello, World !", - "permalink": "docs/1.0.0/foo/baz", - "previous": "version-1.0.0-foo/bar", - "previous_id": "version-1.0.0-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/baz.md", - "title": "Baz", - "version": "1.0.0", - }, - "version-1.0.0-hello": Object { - "category": "Guides", - "id": "version-1.0.0-hello", - "language": undefined, - "localized_id": "version-1.0.0-hello", - "permalink": "docs/1.0.0/hello", - "previous": "version-1.0.0-foo/baz", - "previous_id": "version-1.0.0-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/hello.md", - "title": "Hello, World !", - "version": "1.0.0", - }, - "version-1.0.1-foo/bar": Object { - "category": "Test", - "id": "version-1.0.1-foo/bar", - "language": undefined, - "localized_id": "version-1.0.1-foo/bar", - "next": "version-1.0.1-foo/baz", - "next_id": "version-1.0.1-foo/baz", - "next_title": "Baz", - "permalink": "docs/foo/bar", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/bar.md", - "title": "Bar", - "version": "1.0.1", - }, - "version-1.0.1-foo/baz": Object { - "category": "Test", - "id": "version-1.0.1-foo/baz", - "language": undefined, - "localized_id": "version-1.0.1-foo/baz", - "next": "version-1.0.1-hello", - "next_id": "version-1.0.1-hello", - "next_title": "Hello, World !", - "permalink": "docs/foo/baz", - "previous": "version-1.0.1-foo/bar", - "previous_id": "version-1.0.1-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/baz.md", - "title": "Baz", - "version": "1.0.1", - }, - "version-1.0.1-hello": Object { - "category": "Guides", - "id": "version-1.0.1-hello", - "language": undefined, - "localized_id": "version-1.0.1-hello", - "permalink": "docs/hello", - "previous": "version-1.0.1-foo/baz", - "previous_id": "version-1.0.1-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/hello.md", - "title": "Hello, World !", - "version": "1.0.1", - }, + "en-hello": Object { + "id": "en-hello", + "language": "en", + "localized_id": "en-hello", + "permalink": "docs/en/next/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": "next", }, - "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", - "env": Object { - "translation": Object { - "defaultLanguage": Object { - "enabled": true, - "name": "English", - "tag": "en", - }, - "enabled": true, - "enabledLanguages": Array [ - Object { - "enabled": true, - "name": "English", - "tag": "en", - }, - Object { - "enabled": true, - "name": "한국어", - "tag": "ko", - }, - ], - }, - "versioning": Object { - "defaultVersion": "1.0.1", - "enabled": true, - "latestVersion": "1.0.1", - "versions": Array [ - "1.0.1", - "1.0.0", - ], - }, + "foo/bar": Object { + "category": "Test", + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "next": "foo/baz", + "next_id": "foo/baz", + "next_title": "baz", + "permalink": "docs/next/foo/bar", + "sidebar": "docs", + "source": "foo/bar.md", + "title": "Bar", + "version": "next", }, - "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site/build", - "pagesData": Array [ - Object { - "path": "/", - "source": "index.js", - }, - Object { - "path": "/hello/world", - "source": "hello/world.js", - }, - ], - "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site/pages", - "siteConfig": Object { - "baseUrl": "/", - "defaultLanguage": "en", - "organizationName": "endiliey", - "projectName": "hello", - "tagline": "Hello World", - "title": "Hello", + "foo/baz": Object { + "category": "Test", + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "next": "hello", + "next_id": "hello", + "next_title": "Next", + "permalink": "docs/next/foo/baz", + "previous": "foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", + "source": "foo/baz.md", + "title": "baz", + "version": "next", + }, + "ko-version-1.0.0-version-1.0.0/foo/bar": Object { + "id": "ko-version-1.0.0-version-1.0.0/foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/foo/bar", + "permalink": "docs/ko/1.0.0/version-1.0.0/foo/bar", + "source": "ko/version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "ko-version-1.0.0-version-1.0.0/foo/baz": Object { + "id": "ko-version-1.0.0-version-1.0.0/foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/foo/baz", + "permalink": "docs/ko/1.0.0/version-1.0.0/foo/baz", + "source": "ko/version-1.0.0/foo/baz.md", + "title": "baz", + "version": "1.0.0", + }, + "ko-version-1.0.0-version-1.0.0/hello": Object { + "id": "ko-version-1.0.0-version-1.0.0/hello", + "language": "ko", + "localized_id": "ko-version-1.0.0-version-1.0.0/hello", + "permalink": "docs/ko/1.0.0/version-1.0.0/hello", + "source": "ko/version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "ko-version-1.0.1-version-1.0.1/foo/bar": Object { + "id": "ko-version-1.0.1-version-1.0.1/foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/foo/bar", + "permalink": "docs/ko/version-1.0.1/foo/bar", + "source": "ko/version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "ko-version-1.0.1-version-1.0.1/foo/baz": Object { + "id": "ko-version-1.0.1-version-1.0.1/foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/foo/baz", + "permalink": "docs/ko/version-1.0.1/foo/baz", + "source": "ko/version-1.0.1/foo/baz.md", + "title": "baz", + "version": "1.0.1", + }, + "ko-version-1.0.1-version-1.0.1/hello": Object { + "id": "ko-version-1.0.1-version-1.0.1/hello", + "language": "ko", + "localized_id": "ko-version-1.0.1-version-1.0.1/hello", + "permalink": "docs/ko/version-1.0.1/hello", + "source": "ko/version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", + }, + "version-1.0.0-foo/bar": Object { + "category": "Test", + "id": "version-1.0.0-foo/bar", + "language": undefined, + "localized_id": "version-1.0.0-foo/bar", + "next": "version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "Baz", + "permalink": "docs/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "version-1.0.0-foo/baz": Object { + "category": "Test", + "id": "version-1.0.0-foo/baz", + "language": undefined, + "localized_id": "version-1.0.0-foo/baz", + "next": "version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", + "permalink": "docs/1.0.0/foo/baz", + "previous": "version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/baz.md", + "title": "Baz", + "version": "1.0.0", + }, + "version-1.0.0-hello": Object { + "category": "Guides", + "id": "version-1.0.0-hello", + "language": undefined, + "localized_id": "version-1.0.0-hello", + "permalink": "docs/1.0.0/hello", + "previous": "version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "version-1.0.1-foo/bar": Object { + "category": "Test", + "id": "version-1.0.1-foo/bar", + "language": undefined, + "localized_id": "version-1.0.1-foo/bar", + "next": "version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "Baz", + "permalink": "docs/foo/bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "version-1.0.1-foo/baz": Object { + "category": "Test", + "id": "version-1.0.1-foo/baz", + "language": undefined, + "localized_id": "version-1.0.1-foo/baz", + "next": "version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", + "permalink": "docs/foo/baz", + "previous": "version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/baz.md", + "title": "Baz", + "version": "1.0.1", + }, + "version-1.0.1-hello": Object { + "category": "Guides", + "id": "version-1.0.1-hello", + "language": undefined, + "localized_id": "version-1.0.1-hello", + "permalink": "docs/hello", + "previous": "version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", }, - "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/transversioned-site", - "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", } `; exports[`loadDocs versioned website 1`] = ` Object { - "baseUrl": "/", - "docsData": Object { - "foo/bar": Object { - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "permalink": "docs/next/foo/bar", - "source": "foo/bar.md", - "title": "Bar", - "version": "next", - }, - "foo/baz": Object { - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "permalink": "docs/next/foo/baz", - "source": "foo/baz.md", - "title": "baz", - "version": "next", - }, - "hello": Object { - "id": "hello", - "language": undefined, - "localized_id": "hello", - "permalink": "docs/next/hello", - "source": "hello.md", - "title": "Hello, World !", - "version": "next", - }, - "version-1.0.0-foo/bar": Object { - "category": "Test", - "id": "version-1.0.0-foo/bar", - "language": undefined, - "localized_id": "version-1.0.0-foo/bar", - "next": "version-1.0.0-foo/baz", - "next_id": "version-1.0.0-foo/baz", - "next_title": "Baz", - "permalink": "docs/1.0.0/foo/bar", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/bar.md", - "title": "Bar", - "version": "1.0.0", - }, - "version-1.0.0-foo/baz": Object { - "category": "Test", - "id": "version-1.0.0-foo/baz", - "language": undefined, - "localized_id": "version-1.0.0-foo/baz", - "next": "version-1.0.0-hello", - "next_id": "version-1.0.0-hello", - "next_title": "Hello, World !", - "permalink": "docs/1.0.0/foo/baz", - "previous": "version-1.0.0-foo/bar", - "previous_id": "version-1.0.0-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/baz.md", - "title": "Baz", - "version": "1.0.0", - }, - "version-1.0.0-hello": Object { - "category": "Guides", - "id": "version-1.0.0-hello", - "language": undefined, - "localized_id": "version-1.0.0-hello", - "permalink": "docs/1.0.0/hello", - "previous": "version-1.0.0-foo/baz", - "previous_id": "version-1.0.0-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/hello.md", - "title": "Hello, World !", - "version": "1.0.0", - }, - "version-1.0.1-foo/bar": Object { - "category": "Test", - "id": "version-1.0.1-foo/bar", - "language": undefined, - "localized_id": "version-1.0.1-foo/bar", - "next": "version-1.0.1-foo/baz", - "next_id": "version-1.0.1-foo/baz", - "next_title": "Baz", - "permalink": "docs/foo/bar", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/bar.md", - "title": "Bar", - "version": "1.0.1", - }, - "version-1.0.1-foo/baz": Object { - "category": "Test", - "id": "version-1.0.1-foo/baz", - "language": undefined, - "localized_id": "version-1.0.1-foo/baz", - "next": "version-1.0.1-hello", - "next_id": "version-1.0.1-hello", - "next_title": "Hello, World !", - "permalink": "docs/foo/baz", - "previous": "version-1.0.1-foo/bar", - "previous_id": "version-1.0.1-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/baz.md", - "title": "Baz", - "version": "1.0.1", - }, - "version-1.0.1-hello": Object { - "category": "Guides", - "id": "version-1.0.1-hello", - "language": undefined, - "localized_id": "version-1.0.1-hello", - "permalink": "docs/hello", - "previous": "version-1.0.1-foo/baz", - "previous_id": "version-1.0.1-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/hello.md", - "title": "Hello, World !", - "version": "1.0.1", - }, + "foo/bar": Object { + "id": "foo/bar", + "language": undefined, + "localized_id": "foo/bar", + "permalink": "docs/next/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": "next", }, - "docsDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/docs", - "env": Object { - "translation": Object { - "defaultLanguage": Object {}, - "enabled": false, - "enabledLanguages": Array [], - }, - "versioning": Object { - "defaultVersion": "1.0.1", - "enabled": true, - "latestVersion": "1.0.1", - "versions": Array [ - "1.0.1", - "1.0.0", - ], - }, + "foo/baz": Object { + "id": "foo/baz", + "language": undefined, + "localized_id": "foo/baz", + "permalink": "docs/next/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": "next", }, - "outDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site/build", - "pagesData": Array [ - Object { - "path": "/", - "source": "index.js", - }, - Object { - "path": "/hello/world", - "source": "hello/world.js", - }, - ], - "pagesDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site/pages", - "siteConfig": Object { - "baseUrl": "/", - "organizationName": "endiliey", - "projectName": "hello", - "tagline": "Hello World", - "title": "Hello", + "hello": Object { + "id": "hello", + "language": undefined, + "localized_id": "hello", + "permalink": "docs/next/hello", + "source": "hello.md", + "title": "Hello, World !", + "version": "next", + }, + "version-1.0.0-foo/bar": Object { + "category": "Test", + "id": "version-1.0.0-foo/bar", + "language": undefined, + "localized_id": "version-1.0.0-foo/bar", + "next": "version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "Baz", + "permalink": "docs/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "version-1.0.0-foo/baz": Object { + "category": "Test", + "id": "version-1.0.0-foo/baz", + "language": undefined, + "localized_id": "version-1.0.0-foo/baz", + "next": "version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", + "permalink": "docs/1.0.0/foo/baz", + "previous": "version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/foo/baz.md", + "title": "Baz", + "version": "1.0.0", + }, + "version-1.0.0-hello": Object { + "category": "Guides", + "id": "version-1.0.0-hello", + "language": undefined, + "localized_id": "version-1.0.0-hello", + "permalink": "docs/1.0.0/hello", + "previous": "version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.0-docs", + "source": "version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "version-1.0.1-foo/bar": Object { + "category": "Test", + "id": "version-1.0.1-foo/bar", + "language": undefined, + "localized_id": "version-1.0.1-foo/bar", + "next": "version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "Baz", + "permalink": "docs/foo/bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "version-1.0.1-foo/baz": Object { + "category": "Test", + "id": "version-1.0.1-foo/baz", + "language": undefined, + "localized_id": "version-1.0.1-foo/baz", + "next": "version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", + "permalink": "docs/foo/baz", + "previous": "version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/foo/baz.md", + "title": "Baz", + "version": "1.0.1", + }, + "version-1.0.1-hello": Object { + "category": "Guides", + "id": "version-1.0.1-hello", + "language": undefined, + "localized_id": "version-1.0.1-hello", + "permalink": "docs/hello", + "previous": "version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.1-docs", + "source": "version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", }, - "siteDir": "/mnt/c/Users/endij/Desktop/Linux/munseo/test/__fixtures__/versioned-site", - "themePath": "/mnt/c/Users/endij/Desktop/Linux/munseo/lib/theme", } `; diff --git a/test/load/docs/index.test.js b/test/load/docs/index.test.js index af1a083f1c..6b813794b8 100644 --- a/test/load/docs/index.test.js +++ b/test/load/docs/index.test.js @@ -1,23 +1,32 @@ +import loadDocs from '@lib/load/docs'; import loadSetup from '../../loadSetup'; describe('loadDocs', () => { test('simple website', async () => { const props = await loadSetup('simple'); - expect(props).toMatchSnapshot(); + const {siteDir, docsDir, env} = props; + const docsData = await loadDocs({siteDir, docsDir, env}); + expect(docsData).toMatchSnapshot(); }); test('versioned website', async () => { const props = await loadSetup('versioned'); - expect(props).toMatchSnapshot(); + const {siteDir, docsDir, env} = props; + const docsData = await loadDocs({siteDir, docsDir, env}); + expect(docsData).toMatchSnapshot(); }); test('versioned & translated website', async () => { const props = await loadSetup('transversioned'); - expect(props).toMatchSnapshot(); + const {siteDir, docsDir, env} = props; + const docsData = await loadDocs({siteDir, docsDir, env}); + expect(docsData).toMatchSnapshot(); }); test('translated website', async () => { const props = await loadSetup('translated'); - expect(props).toMatchSnapshot(); + const {siteDir, docsDir, env} = props; + const docsData = await loadDocs({siteDir, docsDir, env}); + expect(docsData).toMatchSnapshot(); }); }); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index 06e80bbcab..171074b259 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -4,12 +4,17 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - const pagesData = await loadPages(pagesDir); + let pagesData = await loadPages(pagesDir); + pagesData.sort((a, b) => a.path > b.path); // because it was unordered expect(pagesData).toEqual([ { path: '/', source: 'index.js' }, + { + path: '/bar/baz', + source: 'bar/baz.js' + }, { path: '/foo', source: 'foo.js' @@ -17,10 +22,6 @@ describe('loadPages', () => { { path: '/foo/', source: 'foo/index.js' - }, - { - path: '/bar/baz', - source: 'bar/baz.js' } ]); expect(pagesData).not.toBeNull(); From 68518002d7c7c80ad860ef867f145da066bbc522 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 7 Sep 2018 22:28:33 +0800 Subject: [PATCH 111/135] fix: docs translation & versioning metadata --- lib/load/docs/metadata.js | 42 ++- .../translated_docs/ko/{docs => }/foo/bar.md | 0 .../translated_docs/ko/{docs => }/foo/baz.md | 0 .../translated_docs/ko/{docs => }/hello.md | 0 .../docs/__snapshots__/index.test.js.snap | 323 ++++++++---------- 5 files changed, 162 insertions(+), 203 deletions(-) rename test/__fixtures__/translated-site/translated_docs/ko/{docs => }/foo/bar.md (100%) rename test/__fixtures__/translated-site/translated_docs/ko/{docs => }/foo/baz.md (100%) rename test/__fixtures__/translated-site/translated_docs/ko/{docs => }/hello.md (100%) diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index 6bffbb5db3..0a2e086af4 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -6,14 +6,16 @@ function getLanguage(filepath, refDir, env) { const translationEnabled = idx(env, ['translation', 'enabled']); if (translationEnabled) { const detectedLangTag = getSubFolder(filepath, refDir); - const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); - if (!detectedLangTag && defaultLanguage && defaultLanguage.tag) { - return defaultLanguage.tag; - } const enabledLanguages = idx(env, ['translation', 'enabledLanguages']); const langTags = (enabledLanguages && enabledLanguages.map(lang => lang.tag)) || []; - return langTags.find(langTag => langTag === detectedLangTag); + if (langTags.includes(detectedLangTag)) { + return detectedLangTag; + } + const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); + if (defaultLanguage && defaultLanguage.tag) { + return defaultLanguage.tag; + } } return undefined; } @@ -22,13 +24,12 @@ function getVersion(filepath, refDir, env) { const versioningEnabled = idx(env, ['versioning', 'enabled']); if (versioningEnabled) { const subFolder = getSubFolder(filepath, refDir); - if (!subFolder) { - return 'next'; - } - const detectedVersion = subFolder.replace(/^version-/, ''); - const versions = idx(env, ['versioning', 'versions']) || []; - if (versions.includes(detectedVersion)) { - return detectedVersion; + if (subFolder) { + const detectedVersion = subFolder.replace(/^version-/, ''); + const versions = idx(env, ['versioning', 'versions']) || []; + if (versions.includes(detectedVersion)) { + return detectedVersion; + } } return 'next'; } @@ -62,7 +63,10 @@ module.exports = async function processMetadata(source, refDir, env, order) { const langPart = (language && `${language}/`) || ''; /* version */ - const versionRefDir = language ? path.join(refDir, language) : refDir; + let versionRefDir = refDir; + if (language && language !== idx(env, ['translation', 'defaultLanguage', 'tag'])) { + versionRefDir = path.join(refDir, language); + } const version = getVersion(filepath, versionRefDir, env); metadata.version = version; const latestVersion = idx(env, ['versioning', 'latestVersion']); @@ -73,6 +77,9 @@ module.exports = async function processMetadata(source, refDir, env, order) { Convert temporarily metadata.id to the form of dirname/id without version/lang prefix ex: file `versioned_docs/version-1.0.0/en/foo/bar.md` with id `version-1.0.0-bar` => `foo/bar` */ + if (language) { + metadata.id = metadata.id.replace(new RegExp(`^${language}-`), ''); + } if (version) { metadata.id = metadata.id.replace(new RegExp(`^version-${version}-`), ''); @@ -81,14 +88,15 @@ module.exports = async function processMetadata(source, refDir, env, order) { const dirName = path.dirname(source); if (dirName !== '.') { let prefix = dirName; - if (version) { - prefix = prefix.replace(new RegExp(`^version-${version}`), ''); - } if (language) { prefix = prefix.replace(new RegExp(`^${language}`), ''); } + prefix = prefix.replace(/^\//, ''); + if (version) { + prefix = prefix.replace(new RegExp(`^version-${version}`), ''); + } + prefix = prefix.replace(/^\//, ''); if (prefix) { - prefix = prefix.replace(/^\//, ''); metadata.id = `${prefix}/${metadata.id}`; } } diff --git a/test/__fixtures__/translated-site/translated_docs/ko/docs/foo/bar.md b/test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/docs/foo/bar.md rename to test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md diff --git a/test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md b/test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/docs/foo/baz.md rename to test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md diff --git a/test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md b/test/__fixtures__/translated-site/translated_docs/ko/hello.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/docs/hello.md rename to test/__fixtures__/translated-site/translated_docs/ko/hello.md diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/test/load/docs/__snapshots__/index.test.js.snap index 76faa67270..4fc6f4a744 100644 --- a/test/load/docs/__snapshots__/index.test.js.snap +++ b/test/load/docs/__snapshots__/index.test.js.snap @@ -34,6 +34,24 @@ Object { exports[`loadDocs translated website 1`] = ` Object { + "en-foo/bar": Object { + "id": "en-foo/bar", + "language": "en", + "localized_id": "en-foo/bar", + "permalink": "docs/en/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": undefined, + }, + "en-foo/baz": Object { + "id": "en-foo/baz", + "language": "en", + "localized_id": "en-foo/baz", + "permalink": "docs/en/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": undefined, + }, "en-hello": Object { "id": "en-hello", "language": "en", @@ -43,48 +61,30 @@ Object { "title": "Hello, World !", "version": undefined, }, - "foo/bar": Object { - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "permalink": "docs/foo/bar", - "source": "foo/bar.md", + "ko-foo/bar": Object { + "id": "ko-foo/bar", + "language": "ko", + "localized_id": "ko-foo/bar", + "permalink": "docs/ko/foo/bar", + "source": "ko/foo/bar.md", "title": "Bar", "version": undefined, }, - "foo/baz": Object { - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "permalink": "docs/foo/baz", - "source": "foo/baz.md", + "ko-foo/baz": Object { + "id": "ko-foo/baz", + "language": "ko", + "localized_id": "ko-foo/baz", + "permalink": "docs/ko/foo/baz", + "source": "ko/foo/baz.md", "title": "baz", "version": undefined, }, - "ko-docs/foo/bar": Object { - "id": "ko-docs/foo/bar", + "ko-hello": Object { + "id": "ko-hello", "language": "ko", - "localized_id": "ko-docs/foo/bar", - "permalink": "docs/ko/docs/foo/bar", - "source": "ko/docs/foo/bar.md", - "title": "Bar", - "version": undefined, - }, - "ko-docs/foo/baz": Object { - "id": "ko-docs/foo/baz", - "language": "ko", - "localized_id": "ko-docs/foo/baz", - "permalink": "docs/ko/docs/foo/baz", - "source": "ko/docs/foo/baz.md", - "title": "baz", - "version": undefined, - }, - "ko-docs/hello": Object { - "id": "ko-docs/hello", - "language": "ko", - "localized_id": "ko-docs/hello", - "permalink": "docs/ko/docs/hello", - "source": "ko/docs/hello.md", + "localized_id": "ko-hello", + "permalink": "docs/ko/hello", + "source": "ko/hello.md", "title": "Hello, World !", "version": undefined, }, @@ -93,6 +93,24 @@ Object { exports[`loadDocs versioned & translated website 1`] = ` Object { + "en-foo/bar": Object { + "id": "en-foo/bar", + "language": "en", + "localized_id": "en-foo/bar", + "permalink": "docs/en/next/foo/bar", + "source": "foo/bar.md", + "title": "Bar", + "version": "next", + }, + "en-foo/baz": Object { + "id": "en-foo/baz", + "language": "en", + "localized_id": "en-foo/baz", + "permalink": "docs/en/next/foo/baz", + "source": "foo/baz.md", + "title": "baz", + "version": "next", + }, "en-hello": Object { "id": "en-hello", "language": "en", @@ -102,181 +120,114 @@ Object { "title": "Hello, World !", "version": "next", }, - "foo/bar": Object { - "category": "Test", - "id": "foo/bar", - "language": undefined, - "localized_id": "foo/bar", - "next": "foo/baz", - "next_id": "foo/baz", - "next_title": "baz", - "permalink": "docs/next/foo/bar", - "sidebar": "docs", - "source": "foo/bar.md", - "title": "Bar", - "version": "next", - }, - "foo/baz": Object { - "category": "Test", - "id": "foo/baz", - "language": undefined, - "localized_id": "foo/baz", - "next": "hello", - "next_id": "hello", - "next_title": "Next", - "permalink": "docs/next/foo/baz", - "previous": "foo/bar", - "previous_id": "foo/bar", - "previous_title": "Bar", - "sidebar": "docs", - "source": "foo/baz.md", - "title": "baz", - "version": "next", - }, - "ko-version-1.0.0-version-1.0.0/foo/bar": Object { - "id": "ko-version-1.0.0-version-1.0.0/foo/bar", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/foo/bar", - "permalink": "docs/ko/1.0.0/version-1.0.0/foo/bar", - "source": "ko/version-1.0.0/foo/bar.md", - "title": "Bar", - "version": "1.0.0", - }, - "ko-version-1.0.0-version-1.0.0/foo/baz": Object { - "id": "ko-version-1.0.0-version-1.0.0/foo/baz", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/foo/baz", - "permalink": "docs/ko/1.0.0/version-1.0.0/foo/baz", - "source": "ko/version-1.0.0/foo/baz.md", - "title": "baz", - "version": "1.0.0", - }, - "ko-version-1.0.0-version-1.0.0/hello": Object { - "id": "ko-version-1.0.0-version-1.0.0/hello", - "language": "ko", - "localized_id": "ko-version-1.0.0-version-1.0.0/hello", - "permalink": "docs/ko/1.0.0/version-1.0.0/hello", - "source": "ko/version-1.0.0/hello.md", - "title": "Hello, World !", - "version": "1.0.0", - }, - "ko-version-1.0.1-version-1.0.1/foo/bar": Object { - "id": "ko-version-1.0.1-version-1.0.1/foo/bar", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/foo/bar", - "permalink": "docs/ko/version-1.0.1/foo/bar", - "source": "ko/version-1.0.1/foo/bar.md", - "title": "Bar", - "version": "1.0.1", - }, - "ko-version-1.0.1-version-1.0.1/foo/baz": Object { - "id": "ko-version-1.0.1-version-1.0.1/foo/baz", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/foo/baz", - "permalink": "docs/ko/version-1.0.1/foo/baz", - "source": "ko/version-1.0.1/foo/baz.md", - "title": "baz", - "version": "1.0.1", - }, - "ko-version-1.0.1-version-1.0.1/hello": Object { - "id": "ko-version-1.0.1-version-1.0.1/hello", - "language": "ko", - "localized_id": "ko-version-1.0.1-version-1.0.1/hello", - "permalink": "docs/ko/version-1.0.1/hello", - "source": "ko/version-1.0.1/hello.md", - "title": "Hello, World !", - "version": "1.0.1", - }, - "version-1.0.0-foo/bar": Object { - "category": "Test", - "id": "version-1.0.0-foo/bar", - "language": undefined, - "localized_id": "version-1.0.0-foo/bar", - "next": "version-1.0.0-foo/baz", - "next_id": "version-1.0.0-foo/baz", - "next_title": "Baz", - "permalink": "docs/1.0.0/foo/bar", - "sidebar": "version-1.0.0-docs", + "en-version-1.0.0-foo/bar": Object { + "id": "en-version-1.0.0-foo/bar", + "language": "en", + "localized_id": "en-version-1.0.0-foo/bar", + "permalink": "docs/en/1.0.0/foo/bar", "source": "version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, - "version-1.0.0-foo/baz": Object { - "category": "Test", - "id": "version-1.0.0-foo/baz", - "language": undefined, - "localized_id": "version-1.0.0-foo/baz", - "next": "version-1.0.0-hello", - "next_id": "version-1.0.0-hello", - "next_title": "Hello, World !", - "permalink": "docs/1.0.0/foo/baz", - "previous": "version-1.0.0-foo/bar", - "previous_id": "version-1.0.0-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.0-docs", + "en-version-1.0.0-foo/baz": Object { + "id": "en-version-1.0.0-foo/baz", + "language": "en", + "localized_id": "en-version-1.0.0-foo/baz", + "permalink": "docs/en/1.0.0/foo/baz", "source": "version-1.0.0/foo/baz.md", "title": "Baz", "version": "1.0.0", }, - "version-1.0.0-hello": Object { - "category": "Guides", - "id": "version-1.0.0-hello", - "language": undefined, - "localized_id": "version-1.0.0-hello", - "permalink": "docs/1.0.0/hello", - "previous": "version-1.0.0-foo/baz", - "previous_id": "version-1.0.0-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.0-docs", + "en-version-1.0.0-hello": Object { + "id": "en-version-1.0.0-hello", + "language": "en", + "localized_id": "en-version-1.0.0-hello", + "permalink": "docs/en/1.0.0/hello", "source": "version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, - "version-1.0.1-foo/bar": Object { - "category": "Test", - "id": "version-1.0.1-foo/bar", - "language": undefined, - "localized_id": "version-1.0.1-foo/bar", - "next": "version-1.0.1-foo/baz", - "next_id": "version-1.0.1-foo/baz", - "next_title": "Baz", - "permalink": "docs/foo/bar", - "sidebar": "version-1.0.1-docs", + "en-version-1.0.1-foo/bar": Object { + "id": "en-version-1.0.1-foo/bar", + "language": "en", + "localized_id": "en-version-1.0.1-foo/bar", + "permalink": "docs/en/foo/bar", "source": "version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, - "version-1.0.1-foo/baz": Object { - "category": "Test", - "id": "version-1.0.1-foo/baz", - "language": undefined, - "localized_id": "version-1.0.1-foo/baz", - "next": "version-1.0.1-hello", - "next_id": "version-1.0.1-hello", - "next_title": "Hello, World !", - "permalink": "docs/foo/baz", - "previous": "version-1.0.1-foo/bar", - "previous_id": "version-1.0.1-foo/bar", - "previous_title": "Bar", - "sidebar": "version-1.0.1-docs", + "en-version-1.0.1-foo/baz": Object { + "id": "en-version-1.0.1-foo/baz", + "language": "en", + "localized_id": "en-version-1.0.1-foo/baz", + "permalink": "docs/en/foo/baz", "source": "version-1.0.1/foo/baz.md", "title": "Baz", "version": "1.0.1", }, - "version-1.0.1-hello": Object { - "category": "Guides", - "id": "version-1.0.1-hello", - "language": undefined, - "localized_id": "version-1.0.1-hello", - "permalink": "docs/hello", - "previous": "version-1.0.1-foo/baz", - "previous_id": "version-1.0.1-foo/baz", - "previous_title": "Baz", - "sidebar": "version-1.0.1-docs", + "en-version-1.0.1-hello": Object { + "id": "en-version-1.0.1-hello", + "language": "en", + "localized_id": "en-version-1.0.1-hello", + "permalink": "docs/en/hello", "source": "version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", }, + "ko-version-1.0.0-foo/bar": Object { + "id": "ko-version-1.0.0-foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.0-foo/bar", + "permalink": "docs/ko/1.0.0/foo/bar", + "source": "ko/version-1.0.0/foo/bar.md", + "title": "Bar", + "version": "1.0.0", + }, + "ko-version-1.0.0-foo/baz": Object { + "id": "ko-version-1.0.0-foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.0-foo/baz", + "permalink": "docs/ko/1.0.0/foo/baz", + "source": "ko/version-1.0.0/foo/baz.md", + "title": "baz", + "version": "1.0.0", + }, + "ko-version-1.0.0-hello": Object { + "id": "ko-version-1.0.0-hello", + "language": "ko", + "localized_id": "ko-version-1.0.0-hello", + "permalink": "docs/ko/1.0.0/hello", + "source": "ko/version-1.0.0/hello.md", + "title": "Hello, World !", + "version": "1.0.0", + }, + "ko-version-1.0.1-foo/bar": Object { + "id": "ko-version-1.0.1-foo/bar", + "language": "ko", + "localized_id": "ko-version-1.0.1-foo/bar", + "permalink": "docs/ko/foo/bar", + "source": "ko/version-1.0.1/foo/bar.md", + "title": "Bar", + "version": "1.0.1", + }, + "ko-version-1.0.1-foo/baz": Object { + "id": "ko-version-1.0.1-foo/baz", + "language": "ko", + "localized_id": "ko-version-1.0.1-foo/baz", + "permalink": "docs/ko/foo/baz", + "source": "ko/version-1.0.1/foo/baz.md", + "title": "baz", + "version": "1.0.1", + }, + "ko-version-1.0.1-hello": Object { + "id": "ko-version-1.0.1-hello", + "language": "ko", + "localized_id": "ko-version-1.0.1-hello", + "permalink": "docs/ko/hello", + "source": "ko/version-1.0.1/hello.md", + "title": "Hello, World !", + "version": "1.0.1", + }, } `; From 59fa427dbdc9ca528b5de88ae1b0a2b919fbfe32 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 8 Sep 2018 00:41:17 +0800 Subject: [PATCH 112/135] test: add metadata test --- test/load/__fixtures__/simple-docs/foo/bar.md | 66 --------- test/load/__fixtures__/simple-docs/foo/baz.md | 77 ---------- test/load/__fixtures__/simple-docs/hello.md | 40 ----- test/load/docs/metadata.test.js | 138 ++++++++++++++++++ 4 files changed, 138 insertions(+), 183 deletions(-) delete mode 100644 test/load/__fixtures__/simple-docs/foo/bar.md delete mode 100644 test/load/__fixtures__/simple-docs/foo/baz.md delete mode 100644 test/load/__fixtures__/simple-docs/hello.md create mode 100644 test/load/docs/metadata.test.js diff --git a/test/load/__fixtures__/simple-docs/foo/bar.md b/test/load/__fixtures__/simple-docs/foo/bar.md deleted file mode 100644 index 9f978009c5..0000000000 --- a/test/load/__fixtures__/simple-docs/foo/bar.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -id: bar -title: Bar ---- - -# Remarkable - -> Experience real-time editing with Remarkable! - -Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results. - -*** - -# h1 Heading -## h2 Heading -### h3 Heading -#### h4 Heading -##### h5 Heading -###### h6 Heading - - -## Horizontal Rules - -___ - -*** - -*** - - -## Typographic replacements - -Enable typographer option to see result. - -(c) (C) (r) (R) (tm) (TM) (p) (P) +- - -test.. test... test..... test?..... test!.... - -!!!!!! ???? ,, - -Remarkable -- awesome - -"Smartypants, double quotes" - -'Smartypants, single quotes' - - -## Emphasis - -**This is bold text** - -__This is bold text__ - -*This is italic text* - -_This is italic text_ - -~~Deleted text~~ - -Superscript: 19^th^ - -Subscript: H~2~O - -++Inserted text++ - -==Marked text== diff --git a/test/load/__fixtures__/simple-docs/foo/baz.md b/test/load/__fixtures__/simple-docs/foo/baz.md deleted file mode 100644 index add729c51d..0000000000 --- a/test/load/__fixtures__/simple-docs/foo/baz.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: baz -title: baz ---- - -## Images - -![Minion](/img/minion.png) -![Stormtroopocat](/img/stormtroopocat.jpg) - -Like links, Images also have a footnote style syntax - -![Alt text][id] - -With a reference later in the document defining the URL location: - -[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" - -## Links - -[link text](http://dev.nodeca.com) - -[link with title](http://nodeca.github.io/pica/demo/ "title text!") - -Autoconverted link https://github.com/nodeca/pica (enable linkify to see) - - - -## Footnotes - -Footnote 1 link[^first]. - -Footnote 2 link[^second]. - -Inline footnote^[Text of inline footnote] definition. - -Duplicated footnote reference[^second]. - -[^first]: Footnote **can have markup** - - and multiple paragraphs. - -[^second]: Footnote text. - - -## Definition lists - -Term 1 - -: Definition 1 -with lazy continuation. - -Term 2 with *inline markup* - -: Definition 2 - - { some code, part of Definition 2 } - - Third paragraph of definition 2. - -_Compact style:_ - -Term 1 - ~ Definition 1 - -Term 2 - ~ Definition 2a - ~ Definition 2b - - -## Abbreviations - -This is HTML abbreviation example. - -It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. - -*[HTML]: Hyper Text Markup Language diff --git a/test/load/__fixtures__/simple-docs/hello.md b/test/load/__fixtures__/simple-docs/hello.md deleted file mode 100644 index a392b2ca54..0000000000 --- a/test/load/__fixtures__/simple-docs/hello.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: hello -title: Hello, World ! ---- - -Hi, Endilie here :) - -## Blockquotes - -> Blockquotes can also be nested... ->> ...by using additional greater-than signs right next to each other... -> > > ...or with spaces between arrows. - - -## Lists - -Unordered - -+ Create a list by starting a line with `+`, `-`, or `*` -+ Sub-lists are made by indenting 2 spaces: - - Marker character change forces new list start: - * Ac tristique libero volutpat at - + Facilisis in pretium nisl aliquet - - Nulla volutpat aliquam velit -+ Very easy! - -Ordered - -1. Lorem ipsum dolor sit amet -2. Consectetur adipiscing elit -3. Integer molestie lorem at massa - - -1. You can use sequential numbers... -1. ...or keep all the numbers as `1.` - -Start numbering with offset: - -57. foo -1. bar diff --git a/test/load/docs/metadata.test.js b/test/load/docs/metadata.test.js new file mode 100644 index 0000000000..b1aff83a69 --- /dev/null +++ b/test/load/docs/metadata.test.js @@ -0,0 +1,138 @@ +import path from 'path'; +import processMetadata from '@lib/load/docs/metadata'; +import loadSetup from '../../loadSetup'; + +describe('processMetadata', () => { + test('normal docs', async () => { + const props = await loadSetup('simple'); + const {docsDir, env} = props; + const sourceA = path.join('foo', 'bar.md'); + const sourceB = path.join('hello.md'); + const dataA = await processMetadata(sourceA, docsDir, env, {}); + const dataB = await processMetadata(sourceB, docsDir, env, {}); + expect(dataA).toEqual({ + id: 'foo/bar', + language: undefined, + localized_id: 'foo/bar', + permalink: 'docs/foo/bar', + source: 'foo/bar.md', + title: 'Bar', + version: undefined + }); + expect(dataB).toEqual({ + id: 'hello', + language: undefined, + localized_id: 'hello', + permalink: 'docs/hello', + source: 'hello.md', + title: 'Hello, World !', + version: undefined + }); + }); + + test('versioned docs (without translation)', async () => { + const props = await loadSetup('versioned'); + const {siteDir, docsDir, env} = props; + const refDir = path.join(siteDir, 'versioned_docs'); + const sourceA = path.join('version-1.0.0', 'foo', 'bar.md'); + const sourceB = path.join('version-1.0.0', 'hello.md'); + const dataA = await processMetadata(sourceA, refDir, env, {}); + const dataB = await processMetadata(sourceB, refDir, env, {}); + expect(dataA).toEqual({ + id: 'version-1.0.0-foo/bar', + language: undefined, + localized_id: 'version-1.0.0-foo/bar', + permalink: 'docs/1.0.0/foo/bar', + source: 'version-1.0.0/foo/bar.md', + title: 'Bar', + version: '1.0.0' + }); + expect(dataB).toEqual({ + id: 'version-1.0.0-hello', + language: undefined, + localized_id: 'version-1.0.0-hello', + permalink: 'docs/1.0.0/hello', + source: 'version-1.0.0/hello.md', + title: 'Hello, World !', + version: '1.0.0' + }); + }); + + test('translated versioned docs', async () => { + const props = await loadSetup('transversioned'); + const {siteDir, docsDir, env} = props; + const refDir = path.join(siteDir, 'translated_docs'); + const sourceA = path.join('ko', 'version-1.0.0', 'foo', 'bar.md'); + const sourceB = path.join('ko', 'version-1.0.0', 'hello.md'); + const sourceC = path.join('ko', 'version-1.0.1', 'foo', 'bar.md'); + const sourceD = path.join('ko', 'version-1.0.1', 'hello.md'); + const dataA = await processMetadata(sourceA, refDir, env, {}); + const dataB = await processMetadata(sourceB, refDir, env, {}); + const dataC = await processMetadata(sourceC, refDir, env, {}); + const dataD = await processMetadata(sourceD, refDir, env, {}); + expect(dataA).toEqual({ + id: 'ko-version-1.0.0-foo/bar', + language: 'ko', + localized_id: 'ko-version-1.0.0-foo/bar', + permalink: 'docs/ko/1.0.0/foo/bar', + source: 'ko/version-1.0.0/foo/bar.md', + title: 'Bar', + version: '1.0.0' + }); + expect(dataB).toEqual({ + id: 'ko-version-1.0.0-hello', + language: 'ko', + localized_id: 'ko-version-1.0.0-hello', + permalink: 'docs/ko/1.0.0/hello', + source: 'ko/version-1.0.0/hello.md', + title: 'Hello, World !', + version: '1.0.0' + }); + expect(dataC).toEqual({ + id: 'ko-version-1.0.1-foo/bar', + language: 'ko', + localized_id: 'ko-version-1.0.1-foo/bar', + permalink: 'docs/ko/foo/bar', + source: 'ko/version-1.0.1/foo/bar.md', + title: 'Bar', + version: '1.0.1' + }); + expect(dataD).toEqual({ + id: 'ko-version-1.0.1-hello', + language: 'ko', + localized_id: 'ko-version-1.0.1-hello', + permalink: 'docs/ko/hello', + source: 'ko/version-1.0.1/hello.md', + title: 'Hello, World !', + version: '1.0.1' + }); + }); + + test('translated docs only', async () => { + const props = await loadSetup('translated'); + const {siteDir, docsDir, env} = props; + const refDir = path.join(siteDir, 'translated_docs'); + const sourceA = path.join('ko', 'foo', 'bar.md'); + const sourceB = path.join('ko', 'hello.md'); + const dataA = await processMetadata(sourceA, refDir, env, {}); + const dataB = await processMetadata(sourceB, refDir, env, {}); + expect(dataA).toEqual({ + id: 'ko-foo/bar', + language: 'ko', + localized_id: 'ko-foo/bar', + permalink: 'docs/ko/foo/bar', + source: 'ko/foo/bar.md', + title: 'Bar', + version: undefined + }); + expect(dataB).toEqual({ + id: 'ko-hello', + language: 'ko', + localized_id: 'ko-hello', + permalink: 'docs/ko/hello', + source: 'ko/hello.md', + title: 'Hello, World !', + version: undefined + }); + }); +}); From 185f7b1ed14ca79c11fe6b6047fedc60fb6d8568 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 8 Sep 2018 00:46:15 +0800 Subject: [PATCH 113/135] fix: yarn build error --- lib/load/docs/metadata.js | 5 ++++- lib/webpack/server.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index 0a2e086af4..550303f427 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -64,7 +64,10 @@ module.exports = async function processMetadata(source, refDir, env, order) { /* version */ let versionRefDir = refDir; - if (language && language !== idx(env, ['translation', 'defaultLanguage', 'tag'])) { + if ( + language && + language !== idx(env, ['translation', 'defaultLanguage', 'tag']) + ) { versionRefDir = path.join(refDir, language); } const version = getVersion(filepath, versionRefDir, env); diff --git a/lib/webpack/server.js b/lib/webpack/server.js index d55481ffd0..ce2af23d87 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -17,7 +17,10 @@ module.exports = function createServerConfig(props) { const {siteConfig, docsData, pagesData} = props; // static site generator webpack plugin - const paths = [...docsData, ...pagesData].map(data => data.path); + const docsLinks = Object.values(docsData).map(data => ({ + path: `${siteConfig.baseUrl}${data.permalink}` + })); + const paths = [...docsLinks, ...pagesData].map(data => data.path); config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', From b99605f725ece84598eaf7ed4298afdcca4a7f2c Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 12 Sep 2018 01:00:31 +0800 Subject: [PATCH 114/135] feat: allow custom docsUrl & custom permalink --- lib/load/config.js | 14 +- lib/load/docs/index.js | 55 +++--- lib/load/docs/metadata.js | 50 ++++-- lib/load/index.js | 2 +- lib/load/routes.js | 26 +-- test/__fixtures__/docs/permalink.md | 7 + .../__fixtures__/wrong-site/siteConfig.js | 21 +-- test/load/config.test.js | 2 +- .../docs/__snapshots__/index.test.js.snap | 168 +++++++++++------- test/load/docs/index.test.js | 16 +- test/load/docs/metadata.test.js | 84 +++++---- test/load/pages.test.js | 2 +- 12 files changed, 270 insertions(+), 177 deletions(-) create mode 100644 test/__fixtures__/docs/permalink.md diff --git a/lib/load/config.js b/lib/load/config.js index 618189db89..1ef863e889 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -24,7 +24,9 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { 'highlight', 'markdownPlugins', 'configureWebpack', - 'chainWebpack' + 'chainWebpack', + 'docsUrl', + 'customFields' ]; const missingFields = requiredFields.filter(field => !config[field]); if (missingFields && missingFields.length > 0) { @@ -33,8 +35,16 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { ); } + /* + User's own array of custom fields, + e.g: if they want to include some field so they can access it later from `props.siteConfig` + */ + const {customFields = []} = config; + + /* We don't allow useless/ not meaningful field */ + const allowedFields = [...requiredFields, ...optionalFields, ...customFields]; const uselessFields = Object.keys(config).filter( - field => ![...requiredFields, ...optionalFields].includes(field) + field => !allowedFields.includes(field) ); if (uselessFields && uselessFields.length > 0) { throw new Error( diff --git a/lib/load/docs/index.js b/lib/load/docs/index.js index ea061c052d..6c4fcef18a 100644 --- a/lib/load/docs/index.js +++ b/lib/load/docs/index.js @@ -5,7 +5,7 @@ const loadSidebars = require('./sidebars'); const processMetadata = require('./metadata'); const {getSubFolder, idx} = require('../utils'); -async function loadDocs({siteDir, docsDir, env}) { +async function loadDocs({siteDir, docsDir, env, siteConfig}) { // @tested - load all sidebars including versioned sidebars const allSidebars = loadSidebars({siteDir, env}); @@ -18,8 +18,7 @@ async function loadDocs({siteDir, docsDir, env}) { translationEnabled && idx(env, ['translation', 'enabledLanguages']); const enabledLangTags = (enabledLanguages && enabledLanguages.map(lang => lang.tag)) || []; - const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); - const defaultLangTag = defaultLanguage && defaultLanguage.tag; + const defaultLangTag = idx(env, ['translation', 'defaultLanguage', 'tag']); const versioningEnabled = idx(env, ['versioning', 'enabled']); const versions = (versioningEnabled && idx(env, ['versioning', 'versions'])) || []; @@ -43,7 +42,13 @@ async function loadDocs({siteDir, docsDir, env}) { throw new Error(`You cannot have a folder named 'docs/${subFolder}/'`); } - const metadata = await processMetadata(source, docsDir, env, order); + const metadata = await processMetadata( + source, + docsDir, + env, + order, + siteConfig + ); metadatas[metadata.id] = metadata; }) ); @@ -57,7 +62,7 @@ async function loadDocs({siteDir, docsDir, env}) { translatedFiles.map(async source => { /* Do not process disabled & default languages folder in `translated_docs` - e.g: 'translated_docs/ja/**' should not be allowed if lang 'ja' is disabled + e.g: 'translated_docs/ja/**' should not be processed if lang 'ja' is disabled */ const translatedFilePath = path.resolve(translatedDir, source); const detectedLangTag = getSubFolder(translatedFilePath, translatedDir); @@ -68,7 +73,13 @@ async function loadDocs({siteDir, docsDir, env}) { return; } - const metadata = await processMetadata(source, translatedDir, env, order); + const metadata = await processMetadata( + source, + translatedDir, + env, + order, + siteConfig + ); metadatas[metadata.id] = metadata; }) ); @@ -80,7 +91,13 @@ async function loadDocs({siteDir, docsDir, env}) { }); await Promise.all( versionedFiles.map(async source => { - const metadata = await processMetadata(source, versionedDir, env, order); + const metadata = await processMetadata( + source, + versionedDir, + env, + order, + siteConfig + ); metadatas[metadata.id] = metadata; }) ); @@ -88,22 +105,16 @@ async function loadDocs({siteDir, docsDir, env}) { /* Get the titles of the previous and next ids so that we can use them */ - Object.keys(metadatas).forEach(metadata => { - if (metadatas[metadata].previous) { - if (metadatas[metadatas[metadata].previous]) { - metadatas[metadata].previous_title = - metadatas[metadatas[metadata].previous].title; - } else { - metadatas[metadata].previous_title = 'Previous'; - } + Object.keys(metadatas).forEach(currentID => { + const previousID = idx(metadatas, [currentID, 'previous']); + if (previousID) { + const previousTitle = idx(metadatas, [previousID, 'title']); + metadatas[currentID].previous_title = previousTitle || 'Previous'; } - if (metadatas[metadata].next) { - if (metadatas[metadatas[metadata].next]) { - metadatas[metadata].next_title = - metadatas[metadatas[metadata].next].title; - } else { - metadatas[metadata].next_title = 'Next'; - } + const nextID = idx(metadatas, [currentID, 'next']); + if (nextID) { + const nextTitle = idx(metadatas, [nextID, 'title']); + metadatas[currentID].next_title = nextTitle || 'Next'; } }); diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index 550303f427..82a0e1b596 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -36,14 +36,17 @@ function getVersion(filepath, refDir, env) { return undefined; } -module.exports = async function processMetadata(source, refDir, env, order) { +module.exports = async function processMetadata( + source, + refDir, + env, + order, + siteConfig +) { const filepath = path.resolve(refDir, source); const fileString = await fs.readFile(filepath, 'utf-8'); const {metadata} = parse(fileString); - /* source (relative to refDir) */ - metadata.source = source; - /* default id is the file name */ if (!metadata.id) { metadata.id = path.basename(source, path.extname(source)); @@ -63,11 +66,9 @@ module.exports = async function processMetadata(source, refDir, env, order) { const langPart = (language && `${language}/`) || ''; /* version */ + const defaultLangTag = idx(env, ['translation', 'defaultLanguage', 'tag']); let versionRefDir = refDir; - if ( - language && - language !== idx(env, ['translation', 'defaultLanguage', 'tag']) - ) { + if (language && language !== defaultLangTag) { versionRefDir = path.join(refDir, language); } const version = getVersion(filepath, versionRefDir, env); @@ -104,8 +105,37 @@ module.exports = async function processMetadata(source, refDir, env, order) { } } - /* Build the permalink without baseUrl */ - metadata.permalink = `docs/${langPart}${versionPart}${metadata.id}`; + /* + The docs file source + e.g: `@docs/hello.md` or `@versioned_docs/version-1.0.0/hello.md` + */ + if (language && language !== defaultLangTag) { + metadata.source = `@translated_docs/${source}`; + } else if (version && version !== 'next') { + metadata.source = `@versioned_docs/${source}`; + } else { + metadata.source = `@docs/${source}`; + } + + /* Build the permalink */ + const {baseUrl, docsUrl = 'docs'} = siteConfig; + + /* + if user has own custom permalink defined in frontmatter + e.g: :baseUrl:docsUrl/:langPart:versionPartendiliey/:id + */ + if (metadata.permalink) { + metadata.permalink = metadata.permalink + .replace(/:baseUrl/, baseUrl) + .replace(/:docsUrl/, docsUrl) + .replace(/:langPart/, langPart) + .replace(/:versionPart/, versionPart) + .replace(/:id/, metadata.id); + } else { + metadata.permalink = `${baseUrl}${docsUrl}/${langPart}${versionPart}${ + metadata.id + }`; + } /* if version */ if (version && version !== 'next') { diff --git a/lib/load/index.js b/lib/load/index.js index 6e2d381ac7..f6c6190ae3 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -20,7 +20,7 @@ module.exports = async function load(siteDir) { '..', siteConfig.customDocsPath || 'docs' ); - const docsData = await loadDocs({siteDir, docsDir, env}); + const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); await generate( 'docsData.js', `export default ${JSON.stringify(docsData, null, 2)};` diff --git a/lib/load/routes.js b/lib/load/routes.js index 42193e0631..d615960652 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,30 +1,12 @@ -const {idx} = require('./utils'); - -async function genRoutesConfig({ - docsData = {}, - pagesData = [], - env, - siteConfig -}) { +async function genRoutesConfig({docsData = {}, pagesData = []}) { function genDocsRoute(metadata) { - const {permalink, source, version, language} = metadata; - const defaultLanguage = idx(env, ['translation', 'defaultLanguage']); - let importPath = `@docs/${source}`; - if (language && language !== defaultLanguage.tag) { - importPath = `@translated_docs/${source}`; - } else if (version && version !== 'next') { - importPath = `@versioned_docs/${source}`; - } - - const {baseUrl} = siteConfig; - const docsPath = `${baseUrl}${permalink}`; - + const {permalink, source} = metadata; return ` { - path: ${JSON.stringify(docsPath)}, + path: ${JSON.stringify(permalink)}, exact: true, component: Loadable({ - loader: () => import(${JSON.stringify(importPath)}), + loader: () => import(${JSON.stringify(source)}), loading: Loading, render(loaded, props) { let Content = loaded.default; diff --git a/test/__fixtures__/docs/permalink.md b/test/__fixtures__/docs/permalink.md new file mode 100644 index 0000000000..3caa3d5d95 --- /dev/null +++ b/test/__fixtures__/docs/permalink.md @@ -0,0 +1,7 @@ +--- +id: permalink +title: Permalink +permalink: :baseUrl:docsUrl/:langPart:versionPartendiliey/:id +--- + +This has a different permalink \ No newline at end of file diff --git a/test/load/__fixtures__/wrong-site/siteConfig.js b/test/load/__fixtures__/wrong-site/siteConfig.js index c84b9e4594..49d6f120be 100644 --- a/test/load/__fixtures__/wrong-site/siteConfig.js +++ b/test/load/__fixtures__/wrong-site/siteConfig.js @@ -1,10 +1,11 @@ -module.exports = { - title: 'Hello', - tagline: 'Hello World', - organizationName: 'endiliey', - projectName: 'hello', - baseUrl: '/', - useLessField: 'what', - superman: 'lol', - admin: 'endi' -}; +module.exports = { + title: 'Hello', + tagline: 'Hello World', + organizationName: 'endiliey', + projectName: 'hello', + baseUrl: '/', + useLessField: 'what', + superman: 'lol', + admin: 'endi', + customFields: ['admin', 'superman'] +}; diff --git a/test/load/config.test.js b/test/load/config.test.js index 817346229f..41d1ed0fc6 100644 --- a/test/load/config.test.js +++ b/test/load/config.test.js @@ -29,7 +29,7 @@ describe('loadConfig', () => { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"useLessField, superman, admin fields are useless in siteConfig.js"` + `"useLessField fields are useless in siteConfig.js"` ); }); diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/test/load/docs/__snapshots__/index.test.js.snap index 4fc6f4a744..4bbac6aa0c 100644 --- a/test/load/docs/__snapshots__/index.test.js.snap +++ b/test/load/docs/__snapshots__/index.test.js.snap @@ -6,8 +6,8 @@ Object { "id": "foo/bar", "language": undefined, "localized_id": "foo/bar", - "permalink": "docs/foo/bar", - "source": "foo/bar.md", + "permalink": "/docs/foo/bar", + "source": "@docs/foo/bar.md", "title": "Bar", "version": undefined, }, @@ -15,8 +15,8 @@ Object { "id": "foo/baz", "language": undefined, "localized_id": "foo/baz", - "permalink": "docs/foo/baz", - "source": "foo/baz.md", + "permalink": "/docs/foo/baz", + "source": "@docs/foo/baz.md", "title": "baz", "version": undefined, }, @@ -24,11 +24,20 @@ Object { "id": "hello", "language": undefined, "localized_id": "hello", - "permalink": "docs/hello", - "source": "hello.md", + "permalink": "/docs/hello", + "source": "@docs/hello.md", "title": "Hello, World !", "version": undefined, }, + "permalink": Object { + "id": "permalink", + "language": undefined, + "localized_id": "permalink", + "permalink": "/docs/endiliey/permalink", + "source": "@docs/permalink.md", + "title": "Permalink", + "version": undefined, + }, } `; @@ -38,8 +47,8 @@ Object { "id": "en-foo/bar", "language": "en", "localized_id": "en-foo/bar", - "permalink": "docs/en/foo/bar", - "source": "foo/bar.md", + "permalink": "/docs/en/foo/bar", + "source": "@docs/foo/bar.md", "title": "Bar", "version": undefined, }, @@ -47,8 +56,8 @@ Object { "id": "en-foo/baz", "language": "en", "localized_id": "en-foo/baz", - "permalink": "docs/en/foo/baz", - "source": "foo/baz.md", + "permalink": "/docs/en/foo/baz", + "source": "@docs/foo/baz.md", "title": "baz", "version": undefined, }, @@ -56,17 +65,26 @@ Object { "id": "en-hello", "language": "en", "localized_id": "en-hello", - "permalink": "docs/en/hello", - "source": "hello.md", + "permalink": "/docs/en/hello", + "source": "@docs/hello.md", "title": "Hello, World !", "version": undefined, }, + "en-permalink": Object { + "id": "en-permalink", + "language": "en", + "localized_id": "en-permalink", + "permalink": "/docs/en/endiliey/permalink", + "source": "@docs/permalink.md", + "title": "Permalink", + "version": undefined, + }, "ko-foo/bar": Object { "id": "ko-foo/bar", "language": "ko", "localized_id": "ko-foo/bar", - "permalink": "docs/ko/foo/bar", - "source": "ko/foo/bar.md", + "permalink": "/docs/ko/foo/bar", + "source": "@translated_docs/ko/foo/bar.md", "title": "Bar", "version": undefined, }, @@ -74,8 +92,8 @@ Object { "id": "ko-foo/baz", "language": "ko", "localized_id": "ko-foo/baz", - "permalink": "docs/ko/foo/baz", - "source": "ko/foo/baz.md", + "permalink": "/docs/ko/foo/baz", + "source": "@translated_docs/ko/foo/baz.md", "title": "baz", "version": undefined, }, @@ -83,8 +101,8 @@ Object { "id": "ko-hello", "language": "ko", "localized_id": "ko-hello", - "permalink": "docs/ko/hello", - "source": "ko/hello.md", + "permalink": "/docs/ko/hello", + "source": "@translated_docs/ko/hello.md", "title": "Hello, World !", "version": undefined, }, @@ -97,8 +115,8 @@ Object { "id": "en-foo/bar", "language": "en", "localized_id": "en-foo/bar", - "permalink": "docs/en/next/foo/bar", - "source": "foo/bar.md", + "permalink": "/docs/en/next/foo/bar", + "source": "@docs/foo/bar.md", "title": "Bar", "version": "next", }, @@ -106,8 +124,8 @@ Object { "id": "en-foo/baz", "language": "en", "localized_id": "en-foo/baz", - "permalink": "docs/en/next/foo/baz", - "source": "foo/baz.md", + "permalink": "/docs/en/next/foo/baz", + "source": "@docs/foo/baz.md", "title": "baz", "version": "next", }, @@ -115,17 +133,26 @@ Object { "id": "en-hello", "language": "en", "localized_id": "en-hello", - "permalink": "docs/en/next/hello", - "source": "hello.md", + "permalink": "/docs/en/next/hello", + "source": "@docs/hello.md", "title": "Hello, World !", "version": "next", }, + "en-permalink": Object { + "id": "en-permalink", + "language": "en", + "localized_id": "en-permalink", + "permalink": "/docs/en/next/endiliey/permalink", + "source": "@docs/permalink.md", + "title": "Permalink", + "version": "next", + }, "en-version-1.0.0-foo/bar": Object { "id": "en-version-1.0.0-foo/bar", "language": "en", "localized_id": "en-version-1.0.0-foo/bar", - "permalink": "docs/en/1.0.0/foo/bar", - "source": "version-1.0.0/foo/bar.md", + "permalink": "/docs/en/1.0.0/foo/bar", + "source": "@versioned_docs/version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, @@ -133,8 +160,8 @@ Object { "id": "en-version-1.0.0-foo/baz", "language": "en", "localized_id": "en-version-1.0.0-foo/baz", - "permalink": "docs/en/1.0.0/foo/baz", - "source": "version-1.0.0/foo/baz.md", + "permalink": "/docs/en/1.0.0/foo/baz", + "source": "@versioned_docs/version-1.0.0/foo/baz.md", "title": "Baz", "version": "1.0.0", }, @@ -142,8 +169,8 @@ Object { "id": "en-version-1.0.0-hello", "language": "en", "localized_id": "en-version-1.0.0-hello", - "permalink": "docs/en/1.0.0/hello", - "source": "version-1.0.0/hello.md", + "permalink": "/docs/en/1.0.0/hello", + "source": "@versioned_docs/version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, @@ -151,8 +178,8 @@ Object { "id": "en-version-1.0.1-foo/bar", "language": "en", "localized_id": "en-version-1.0.1-foo/bar", - "permalink": "docs/en/foo/bar", - "source": "version-1.0.1/foo/bar.md", + "permalink": "/docs/en/foo/bar", + "source": "@versioned_docs/version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, @@ -160,8 +187,8 @@ Object { "id": "en-version-1.0.1-foo/baz", "language": "en", "localized_id": "en-version-1.0.1-foo/baz", - "permalink": "docs/en/foo/baz", - "source": "version-1.0.1/foo/baz.md", + "permalink": "/docs/en/foo/baz", + "source": "@versioned_docs/version-1.0.1/foo/baz.md", "title": "Baz", "version": "1.0.1", }, @@ -169,8 +196,8 @@ Object { "id": "en-version-1.0.1-hello", "language": "en", "localized_id": "en-version-1.0.1-hello", - "permalink": "docs/en/hello", - "source": "version-1.0.1/hello.md", + "permalink": "/docs/en/hello", + "source": "@versioned_docs/version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", }, @@ -178,8 +205,8 @@ Object { "id": "ko-version-1.0.0-foo/bar", "language": "ko", "localized_id": "ko-version-1.0.0-foo/bar", - "permalink": "docs/ko/1.0.0/foo/bar", - "source": "ko/version-1.0.0/foo/bar.md", + "permalink": "/docs/ko/1.0.0/foo/bar", + "source": "@translated_docs/ko/version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, @@ -187,8 +214,8 @@ Object { "id": "ko-version-1.0.0-foo/baz", "language": "ko", "localized_id": "ko-version-1.0.0-foo/baz", - "permalink": "docs/ko/1.0.0/foo/baz", - "source": "ko/version-1.0.0/foo/baz.md", + "permalink": "/docs/ko/1.0.0/foo/baz", + "source": "@translated_docs/ko/version-1.0.0/foo/baz.md", "title": "baz", "version": "1.0.0", }, @@ -196,8 +223,8 @@ Object { "id": "ko-version-1.0.0-hello", "language": "ko", "localized_id": "ko-version-1.0.0-hello", - "permalink": "docs/ko/1.0.0/hello", - "source": "ko/version-1.0.0/hello.md", + "permalink": "/docs/ko/1.0.0/hello", + "source": "@translated_docs/ko/version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, @@ -205,8 +232,8 @@ Object { "id": "ko-version-1.0.1-foo/bar", "language": "ko", "localized_id": "ko-version-1.0.1-foo/bar", - "permalink": "docs/ko/foo/bar", - "source": "ko/version-1.0.1/foo/bar.md", + "permalink": "/docs/ko/foo/bar", + "source": "@translated_docs/ko/version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, @@ -214,8 +241,8 @@ Object { "id": "ko-version-1.0.1-foo/baz", "language": "ko", "localized_id": "ko-version-1.0.1-foo/baz", - "permalink": "docs/ko/foo/baz", - "source": "ko/version-1.0.1/foo/baz.md", + "permalink": "/docs/ko/foo/baz", + "source": "@translated_docs/ko/version-1.0.1/foo/baz.md", "title": "baz", "version": "1.0.1", }, @@ -223,8 +250,8 @@ Object { "id": "ko-version-1.0.1-hello", "language": "ko", "localized_id": "ko-version-1.0.1-hello", - "permalink": "docs/ko/hello", - "source": "ko/version-1.0.1/hello.md", + "permalink": "/docs/ko/hello", + "source": "@translated_docs/ko/version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", }, @@ -237,8 +264,8 @@ Object { "id": "foo/bar", "language": undefined, "localized_id": "foo/bar", - "permalink": "docs/next/foo/bar", - "source": "foo/bar.md", + "permalink": "/docs/next/foo/bar", + "source": "@docs/foo/bar.md", "title": "Bar", "version": "next", }, @@ -246,8 +273,8 @@ Object { "id": "foo/baz", "language": undefined, "localized_id": "foo/baz", - "permalink": "docs/next/foo/baz", - "source": "foo/baz.md", + "permalink": "/docs/next/foo/baz", + "source": "@docs/foo/baz.md", "title": "baz", "version": "next", }, @@ -255,11 +282,20 @@ Object { "id": "hello", "language": undefined, "localized_id": "hello", - "permalink": "docs/next/hello", - "source": "hello.md", + "permalink": "/docs/next/hello", + "source": "@docs/hello.md", "title": "Hello, World !", "version": "next", }, + "permalink": Object { + "id": "permalink", + "language": undefined, + "localized_id": "permalink", + "permalink": "/docs/next/endiliey/permalink", + "source": "@docs/permalink.md", + "title": "Permalink", + "version": "next", + }, "version-1.0.0-foo/bar": Object { "category": "Test", "id": "version-1.0.0-foo/bar", @@ -268,9 +304,9 @@ Object { "next": "version-1.0.0-foo/baz", "next_id": "version-1.0.0-foo/baz", "next_title": "Baz", - "permalink": "docs/1.0.0/foo/bar", + "permalink": "/docs/1.0.0/foo/bar", "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/bar.md", + "source": "@versioned_docs/version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, @@ -282,12 +318,12 @@ Object { "next": "version-1.0.0-hello", "next_id": "version-1.0.0-hello", "next_title": "Hello, World !", - "permalink": "docs/1.0.0/foo/baz", + "permalink": "/docs/1.0.0/foo/baz", "previous": "version-1.0.0-foo/bar", "previous_id": "version-1.0.0-foo/bar", "previous_title": "Bar", "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/foo/baz.md", + "source": "@versioned_docs/version-1.0.0/foo/baz.md", "title": "Baz", "version": "1.0.0", }, @@ -296,12 +332,12 @@ Object { "id": "version-1.0.0-hello", "language": undefined, "localized_id": "version-1.0.0-hello", - "permalink": "docs/1.0.0/hello", + "permalink": "/docs/1.0.0/hello", "previous": "version-1.0.0-foo/baz", "previous_id": "version-1.0.0-foo/baz", "previous_title": "Baz", "sidebar": "version-1.0.0-docs", - "source": "version-1.0.0/hello.md", + "source": "@versioned_docs/version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, @@ -313,9 +349,9 @@ Object { "next": "version-1.0.1-foo/baz", "next_id": "version-1.0.1-foo/baz", "next_title": "Baz", - "permalink": "docs/foo/bar", + "permalink": "/docs/foo/bar", "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/bar.md", + "source": "@versioned_docs/version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, @@ -327,12 +363,12 @@ Object { "next": "version-1.0.1-hello", "next_id": "version-1.0.1-hello", "next_title": "Hello, World !", - "permalink": "docs/foo/baz", + "permalink": "/docs/foo/baz", "previous": "version-1.0.1-foo/bar", "previous_id": "version-1.0.1-foo/bar", "previous_title": "Bar", "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/foo/baz.md", + "source": "@versioned_docs/version-1.0.1/foo/baz.md", "title": "Baz", "version": "1.0.1", }, @@ -341,12 +377,12 @@ Object { "id": "version-1.0.1-hello", "language": undefined, "localized_id": "version-1.0.1-hello", - "permalink": "docs/hello", + "permalink": "/docs/hello", "previous": "version-1.0.1-foo/baz", "previous_id": "version-1.0.1-foo/baz", "previous_title": "Baz", "sidebar": "version-1.0.1-docs", - "source": "version-1.0.1/hello.md", + "source": "@versioned_docs/version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", }, diff --git a/test/load/docs/index.test.js b/test/load/docs/index.test.js index 6b813794b8..a2fb6e47a7 100644 --- a/test/load/docs/index.test.js +++ b/test/load/docs/index.test.js @@ -4,29 +4,29 @@ import loadSetup from '../../loadSetup'; describe('loadDocs', () => { test('simple website', async () => { const props = await loadSetup('simple'); - const {siteDir, docsDir, env} = props; - const docsData = await loadDocs({siteDir, docsDir, env}); + const {siteDir, docsDir, env, siteConfig} = props; + const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); expect(docsData).toMatchSnapshot(); }); test('versioned website', async () => { const props = await loadSetup('versioned'); - const {siteDir, docsDir, env} = props; - const docsData = await loadDocs({siteDir, docsDir, env}); + const {siteDir, docsDir, env, siteConfig} = props; + const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); expect(docsData).toMatchSnapshot(); }); test('versioned & translated website', async () => { const props = await loadSetup('transversioned'); - const {siteDir, docsDir, env} = props; - const docsData = await loadDocs({siteDir, docsDir, env}); + const {siteDir, docsDir, env, siteConfig} = props; + const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); expect(docsData).toMatchSnapshot(); }); test('translated website', async () => { const props = await loadSetup('translated'); - const {siteDir, docsDir, env} = props; - const docsData = await loadDocs({siteDir, docsDir, env}); + const {siteDir, docsDir, env, siteConfig} = props; + const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); expect(docsData).toMatchSnapshot(); }); }); diff --git a/test/load/docs/metadata.test.js b/test/load/docs/metadata.test.js index b1aff83a69..1791bac108 100644 --- a/test/load/docs/metadata.test.js +++ b/test/load/docs/metadata.test.js @@ -5,17 +5,17 @@ import loadSetup from '../../loadSetup'; describe('processMetadata', () => { test('normal docs', async () => { const props = await loadSetup('simple'); - const {docsDir, env} = props; + const {docsDir, env, siteConfig} = props; const sourceA = path.join('foo', 'bar.md'); const sourceB = path.join('hello.md'); - const dataA = await processMetadata(sourceA, docsDir, env, {}); - const dataB = await processMetadata(sourceB, docsDir, env, {}); + const dataA = await processMetadata(sourceA, docsDir, env, {}, siteConfig); + const dataB = await processMetadata(sourceB, docsDir, env, {}, siteConfig); expect(dataA).toEqual({ id: 'foo/bar', language: undefined, localized_id: 'foo/bar', - permalink: 'docs/foo/bar', - source: 'foo/bar.md', + permalink: '/docs/foo/bar', + source: '@docs/foo/bar.md', title: 'Bar', version: undefined }); @@ -23,27 +23,43 @@ describe('processMetadata', () => { id: 'hello', language: undefined, localized_id: 'hello', - permalink: 'docs/hello', - source: 'hello.md', + permalink: '/docs/hello', + source: '@docs/hello.md', title: 'Hello, World !', version: undefined }); }); + test('docs with custom permalink', async () => { + const props = await loadSetup('simple'); + const {docsDir, env, siteConfig} = props; + const source = path.join('permalink.md'); + const data = await processMetadata(source, docsDir, env, {}, siteConfig); + expect(data).toEqual({ + id: 'permalink', + language: undefined, + localized_id: 'permalink', + permalink: '/docs/endiliey/permalink', + source: '@docs/permalink.md', + title: 'Permalink', + version: undefined + }); + }); + test('versioned docs (without translation)', async () => { const props = await loadSetup('versioned'); - const {siteDir, docsDir, env} = props; + const {siteDir, env, siteConfig} = props; const refDir = path.join(siteDir, 'versioned_docs'); const sourceA = path.join('version-1.0.0', 'foo', 'bar.md'); const sourceB = path.join('version-1.0.0', 'hello.md'); - const dataA = await processMetadata(sourceA, refDir, env, {}); - const dataB = await processMetadata(sourceB, refDir, env, {}); + const dataA = await processMetadata(sourceA, refDir, env, {}, siteConfig); + const dataB = await processMetadata(sourceB, refDir, env, {}, siteConfig); expect(dataA).toEqual({ id: 'version-1.0.0-foo/bar', language: undefined, localized_id: 'version-1.0.0-foo/bar', - permalink: 'docs/1.0.0/foo/bar', - source: 'version-1.0.0/foo/bar.md', + permalink: '/docs/1.0.0/foo/bar', + source: '@versioned_docs/version-1.0.0/foo/bar.md', title: 'Bar', version: '1.0.0' }); @@ -51,8 +67,8 @@ describe('processMetadata', () => { id: 'version-1.0.0-hello', language: undefined, localized_id: 'version-1.0.0-hello', - permalink: 'docs/1.0.0/hello', - source: 'version-1.0.0/hello.md', + permalink: '/docs/1.0.0/hello', + source: '@versioned_docs/version-1.0.0/hello.md', title: 'Hello, World !', version: '1.0.0' }); @@ -60,22 +76,22 @@ describe('processMetadata', () => { test('translated versioned docs', async () => { const props = await loadSetup('transversioned'); - const {siteDir, docsDir, env} = props; + const {siteDir, env, siteConfig} = props; const refDir = path.join(siteDir, 'translated_docs'); const sourceA = path.join('ko', 'version-1.0.0', 'foo', 'bar.md'); const sourceB = path.join('ko', 'version-1.0.0', 'hello.md'); const sourceC = path.join('ko', 'version-1.0.1', 'foo', 'bar.md'); const sourceD = path.join('ko', 'version-1.0.1', 'hello.md'); - const dataA = await processMetadata(sourceA, refDir, env, {}); - const dataB = await processMetadata(sourceB, refDir, env, {}); - const dataC = await processMetadata(sourceC, refDir, env, {}); - const dataD = await processMetadata(sourceD, refDir, env, {}); + const dataA = await processMetadata(sourceA, refDir, env, {}, siteConfig); + const dataB = await processMetadata(sourceB, refDir, env, {}, siteConfig); + const dataC = await processMetadata(sourceC, refDir, env, {}, siteConfig); + const dataD = await processMetadata(sourceD, refDir, env, {}, siteConfig); expect(dataA).toEqual({ id: 'ko-version-1.0.0-foo/bar', language: 'ko', localized_id: 'ko-version-1.0.0-foo/bar', - permalink: 'docs/ko/1.0.0/foo/bar', - source: 'ko/version-1.0.0/foo/bar.md', + permalink: '/docs/ko/1.0.0/foo/bar', + source: '@translated_docs/ko/version-1.0.0/foo/bar.md', title: 'Bar', version: '1.0.0' }); @@ -83,8 +99,8 @@ describe('processMetadata', () => { id: 'ko-version-1.0.0-hello', language: 'ko', localized_id: 'ko-version-1.0.0-hello', - permalink: 'docs/ko/1.0.0/hello', - source: 'ko/version-1.0.0/hello.md', + permalink: '/docs/ko/1.0.0/hello', + source: '@translated_docs/ko/version-1.0.0/hello.md', title: 'Hello, World !', version: '1.0.0' }); @@ -92,8 +108,8 @@ describe('processMetadata', () => { id: 'ko-version-1.0.1-foo/bar', language: 'ko', localized_id: 'ko-version-1.0.1-foo/bar', - permalink: 'docs/ko/foo/bar', - source: 'ko/version-1.0.1/foo/bar.md', + permalink: '/docs/ko/foo/bar', + source: '@translated_docs/ko/version-1.0.1/foo/bar.md', title: 'Bar', version: '1.0.1' }); @@ -101,8 +117,8 @@ describe('processMetadata', () => { id: 'ko-version-1.0.1-hello', language: 'ko', localized_id: 'ko-version-1.0.1-hello', - permalink: 'docs/ko/hello', - source: 'ko/version-1.0.1/hello.md', + permalink: '/docs/ko/hello', + source: '@translated_docs/ko/version-1.0.1/hello.md', title: 'Hello, World !', version: '1.0.1' }); @@ -110,18 +126,18 @@ describe('processMetadata', () => { test('translated docs only', async () => { const props = await loadSetup('translated'); - const {siteDir, docsDir, env} = props; + const {siteDir, env, siteConfig} = props; const refDir = path.join(siteDir, 'translated_docs'); const sourceA = path.join('ko', 'foo', 'bar.md'); const sourceB = path.join('ko', 'hello.md'); - const dataA = await processMetadata(sourceA, refDir, env, {}); - const dataB = await processMetadata(sourceB, refDir, env, {}); + const dataA = await processMetadata(sourceA, refDir, env, {}, siteConfig); + const dataB = await processMetadata(sourceB, refDir, env, {}, siteConfig); expect(dataA).toEqual({ id: 'ko-foo/bar', language: 'ko', localized_id: 'ko-foo/bar', - permalink: 'docs/ko/foo/bar', - source: 'ko/foo/bar.md', + permalink: '/docs/ko/foo/bar', + source: '@translated_docs/ko/foo/bar.md', title: 'Bar', version: undefined }); @@ -129,8 +145,8 @@ describe('processMetadata', () => { id: 'ko-hello', language: 'ko', localized_id: 'ko-hello', - permalink: 'docs/ko/hello', - source: 'ko/hello.md', + permalink: '/docs/ko/hello', + source: '@translated_docs/ko/hello.md', title: 'Hello, World !', version: undefined }); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index 171074b259..d73bdcb57b 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -4,7 +4,7 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - let pagesData = await loadPages(pagesDir); + const pagesData = await loadPages(pagesDir); pagesData.sort((a, b) => a.path > b.path); // because it was unordered expect(pagesData).toEqual([ { From 20f6921b52916799b31fd94223275719f8de66e2 Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 12 Sep 2018 01:08:48 +0800 Subject: [PATCH 115/135] chore: normalize permalink to remove trailing slash if user permalink is not good --- lib/load/docs/metadata.js | 16 +++++++++------- test/__fixtures__/docs/permalink.md | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index 82a0e1b596..165f343140 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -122,15 +122,17 @@ module.exports = async function processMetadata( /* if user has own custom permalink defined in frontmatter - e.g: :baseUrl:docsUrl/:langPart:versionPartendiliey/:id + e.g: :baseUrl:docsUrl/:langPart/:versionPart/endiliey/:id */ if (metadata.permalink) { - metadata.permalink = metadata.permalink - .replace(/:baseUrl/, baseUrl) - .replace(/:docsUrl/, docsUrl) - .replace(/:langPart/, langPart) - .replace(/:versionPart/, versionPart) - .replace(/:id/, metadata.id); + metadata.permalink = path.resolve( + metadata.permalink + .replace(/:baseUrl/, baseUrl) + .replace(/:docsUrl/, docsUrl) + .replace(/:langPart/, langPart) + .replace(/:versionPart/, versionPart) + .replace(/:id/, metadata.id) + ); } else { metadata.permalink = `${baseUrl}${docsUrl}/${langPart}${versionPart}${ metadata.id diff --git a/test/__fixtures__/docs/permalink.md b/test/__fixtures__/docs/permalink.md index 3caa3d5d95..6ca64643b7 100644 --- a/test/__fixtures__/docs/permalink.md +++ b/test/__fixtures__/docs/permalink.md @@ -1,7 +1,7 @@ --- id: permalink title: Permalink -permalink: :baseUrl:docsUrl/:langPart:versionPartendiliey/:id +permalink: :baseUrl:docsUrl/:langPart/:versionPart/endiliey/:id --- This has a different permalink \ No newline at end of file From 5fcc13572cc15f09e438c66b0bb0560b4d31aaae Mon Sep 17 00:00:00 2001 From: endiliey Date: Wed, 12 Sep 2018 01:27:21 +0800 Subject: [PATCH 116/135] fix: default theme url typo --- lib/theme/Layout/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index 10f908e0ea..753d342835 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -8,7 +8,7 @@ export default class Layout extends React.Component { render() { const {children, pagesData, docsData = {}, location} = this.props; const docsLinks = Object.values(docsData).map(data => ({ - path: `${siteConfig.baseUrl}${data.permalink}` + path: `${data.permalink}` })); const routeLinks = [...pagesData, ...docsLinks].map( data => From ca623d7d38b4d0edd34b09a8952d74dae4795bb8 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 01:30:00 +0800 Subject: [PATCH 117/135] fix: provide correct paths for build --- lib/webpack/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webpack/server.js b/lib/webpack/server.js index ce2af23d87..85dec57c62 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -18,7 +18,7 @@ module.exports = function createServerConfig(props) { // static site generator webpack plugin const docsLinks = Object.values(docsData).map(data => ({ - path: `${siteConfig.baseUrl}${data.permalink}` + path: `${data.permalink}` })); const paths = [...docsLinks, ...pagesData].map(data => data.path); config.plugin('siteGenerator').use(staticSiteGenerator, [ From 0365403a7594872d594726e9c5a14f6d88528f18 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 02:58:29 +0800 Subject: [PATCH 118/135] feat: add uglifyjs webpack plugin --- lib/webpack/base.js | 18 +++++++++++++++++- lib/webpack/loader/markdown.js | 14 ++++++-------- package.json | 1 + yarn.lock | 13 +++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 9a52de54af..a6087f838c 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -1,5 +1,6 @@ const Config = require('webpack-chain'); const CSSExtractPlugin = require('mini-css-extract-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const path = require('path'); const mdLoader = require.resolve('./loader/markdown'); @@ -74,7 +75,7 @@ module.exports = function createBaseConfig(props, isServer) { mdRule .use('markdown-loader') .loader(mdLoader) - .options({siteConfig}); + .options({siteConfig, siteDir, docsDir}); const cssRule = config.module.rule('css').test(/\.css$/); if (isProd) { @@ -101,5 +102,20 @@ module.exports = function createBaseConfig(props, isServer) { } ]); + if (isProd) { + config.optimization.minimizer([ + new UglifyJsPlugin({ + cache: true, + uglifyOptions: { + warnings: false, + compress: false, + ecma: 6, + mangle: true, + }, + sourceMap: true + }) + ]); + } + return config; }; diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index 97bafff5dd..6939e6030c 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -3,21 +3,19 @@ const fm = require('front-matter'); module.exports = function(fileString) { const options = getOptions(this); + const {siteConfig, siteDir, docsDir } = options; - const {body} = fm(fileString); - const content = JSON.stringify(body); /* - TODO replace all the markdown linking to correct url depends on whether it's versioned/translated/normal docs - e.g: [test](test.md) become [test](/docs/test) + Process the markdown file content, including replacing all relative markdown links */ - const siteConfig = JSON.stringify(options.siteConfig); - + const {body: content = ''} = fm(fileString); + return ( `import React from 'react';\n` + `import Markdown from '@theme/Markdown'\n` + `export default () => ( - - {${content}} + + {${JSON.stringify(content)}} );` ); diff --git a/package.json b/package.json index b4f92d377e..0257afd7a8 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "semver": "^5.5.0", "static-site-generator-webpack-plugin": "endiliey/static-site-generator-webpack-plugin#master", "style-loader": "^0.22.1", + "uglifyjs-webpack-plugin": "^1.3.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", "webpack-merge": "^4.1.4", diff --git a/yarn.lock b/yarn.lock index 4897e32bd3..d2ac6d5e74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6712,6 +6712,19 @@ uglifyjs-webpack-plugin@^1.2.4: webpack-sources "^1.1.0" worker-farm "^1.5.2" +uglifyjs-webpack-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de" + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + underscore.string@~2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" From 4d10c3b8f3585c9dd7b153ca29ca50ebee3fb86b Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 19:13:17 +0800 Subject: [PATCH 119/135] test: docs ordering from sidebar --- .../docs/__snapshots__/order.test.js.snap | 59 ------------------- test/load/docs/order.test.js | 54 ++++++++++++++++- 2 files changed, 52 insertions(+), 61 deletions(-) delete mode 100644 test/load/docs/__snapshots__/order.test.js.snap diff --git a/test/load/docs/__snapshots__/order.test.js.snap b/test/load/docs/__snapshots__/order.test.js.snap deleted file mode 100644 index 11fb9ace9d..0000000000 --- a/test/load/docs/__snapshots__/order.test.js.snap +++ /dev/null @@ -1,59 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`createOrder should populate docs index from multiple sidebars 1`] = ` -Object { - "doc1": Object { - "category": "Category1", - "next": "doc2", - "previous": undefined, - "sidebar": "docs", - }, - "doc2": Object { - "category": "Category1", - "next": "doc3", - "previous": "doc1", - "sidebar": "docs", - }, - "doc3": Object { - "category": "Category2", - "next": "doc4", - "previous": "doc2", - "sidebar": "docs", - }, - "doc4": Object { - "category": "Category2", - "next": undefined, - "previous": "doc3", - "sidebar": "docs", - }, - "doc5": Object { - "category": "Category1", - "next": undefined, - "previous": undefined, - "sidebar": "otherDocs", - }, -} -`; - -exports[`createOrder should resolve docs from older versions 1`] = ` -Object { - "doc1": Object { - "category": "Category1", - "next": undefined, - "previous": undefined, - "sidebar": "docs", - }, - "version-1.2.3-doc1": Object { - "category": "Category2", - "next": undefined, - "previous": "version-1.2.3-doc2", - "sidebar": "version-1.2.3-docs", - }, - "version-1.2.3-doc2": Object { - "category": "Category1", - "next": "version-1.2.3-doc1", - "previous": undefined, - "sidebar": "version-1.2.3-docs", - }, -} -`; diff --git a/test/load/docs/order.test.js b/test/load/docs/order.test.js index 981c2a00cf..65b2d5388c 100644 --- a/test/load/docs/order.test.js +++ b/test/load/docs/order.test.js @@ -11,7 +11,38 @@ describe('createOrder', () => { Category1: ['doc5'] } }); - expect(result).toMatchSnapshot(); + expect(result).toEqual({ + doc1: { + category: 'Category1', + next: 'doc2', + previous: undefined, + sidebar: 'docs' + }, + doc2: { + category: 'Category1', + next: 'doc3', + previous: 'doc1', + sidebar: 'docs' + }, + doc3: { + category: 'Category2', + next: 'doc4', + previous: 'doc2', + sidebar: 'docs' + }, + doc4: { + category: 'Category2', + next: undefined, + previous: 'doc3', + sidebar: 'docs' + }, + doc5: { + category: 'Category1', + next: undefined, + previous: undefined, + sidebar: 'otherDocs' + } + }); }); test('should resolve docs from older versions', () => { @@ -24,7 +55,26 @@ describe('createOrder', () => { Category2: ['version-1.2.3-doc1'] } }); - expect(result).toMatchSnapshot(); + expect(result).toEqual({ + doc1: { + category: 'Category1', + next: undefined, + previous: undefined, + sidebar: 'docs' + }, + 'version-1.2.3-doc1': { + category: 'Category2', + next: undefined, + previous: 'version-1.2.3-doc2', + sidebar: 'version-1.2.3-docs' + }, + 'version-1.2.3-doc2': { + category: 'Category1', + next: 'version-1.2.3-doc1', + previous: undefined, + sidebar: 'version-1.2.3-docs' + } + }); }); test('edge cases', () => { From 760b9172b0b659db860c24bc5a052fa09834bbb8 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 20:49:50 +0800 Subject: [PATCH 120/135] feat: replace relative markdown link to corrrect url --- docs/hello.md | 14 +++++++++ lib/load/index.js | 13 +++++++- lib/theme/Layout/index.js | 1 - lib/webpack/base.js | 13 +++++--- lib/webpack/loader/markdown.js | 57 ++++++++++++++++++++++++++++++---- 5 files changed, 85 insertions(+), 13 deletions(-) diff --git a/docs/hello.md b/docs/hello.md index dc816910fe..0fd648068b 100644 --- a/docs/hello.md +++ b/docs/hello.md @@ -3,6 +3,20 @@ id: hello title: Hello, World ! --- +## Relative links + +Replace this +[highlight](highlight.md) [docusaurus](docusaurus.md) + +Can't replace this +[file](file.md) + +Do not replace below + +``` +[highlight](highlight.md) [docusaurus](docusaurus.md) +``` + ## Blockquotes > Blockquotes can also be nested... diff --git a/lib/load/index.js b/lib/load/index.js index f6c6190ae3..651975008e 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -26,6 +26,12 @@ module.exports = async function load(siteDir) { `export default ${JSON.stringify(docsData, null, 2)};` ); + /* Create source to permalink mapping */ + const sourceToLink = {}; + Object.values(docsData).forEach(({source, permalink}) => { + sourceToLink[source] = permalink; + }); + // pages const pagesDir = path.resolve(siteDir, 'pages'); const pagesData = await loadPages(pagesDir); @@ -41,6 +47,8 @@ module.exports = async function load(siteDir) { const themePath = loadTheme(siteDir); const baseUrl = siteConfig.baseUrl || '/'; + const versionedDir = path.join(siteDir, 'versioned_docs'); + const translatedDir = path.join(siteDir, 'translated_docs'); const props = { siteConfig, @@ -52,7 +60,10 @@ module.exports = async function load(siteDir) { pagesData, outDir, themePath, - baseUrl + baseUrl, + sourceToLink, + versionedDir, + translatedDir }; // Generate React Router Config diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index 753d342835..dd3fbffc78 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -1,6 +1,5 @@ import React from 'react'; import {Link} from 'react-router-dom'; -import siteConfig from '@site/siteConfig'; import styles from './styles.css'; /* eslint-disable react/prefer-stateless-function */ diff --git a/lib/webpack/base.js b/lib/webpack/base.js index a6087f838c..9913fe9a31 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -13,6 +13,9 @@ module.exports = function createBaseConfig(props, isServer) { docsDir, pagesDir, siteDir, + sourceToLink, + versionedDir, + translatedDir, baseUrl } = props; @@ -33,8 +36,8 @@ module.exports = function createBaseConfig(props, isServer) { .set('symlinks', true) .alias.set('@theme', themePath) .set('@site', siteDir) - .set('@versioned_docs', path.resolve(siteDir, 'versioned_docs')) - .set('@translated_docs', path.resolve(siteDir, 'translated_docs')) + .set('@versioned_docs', versionedDir) + .set('@translated_docs', translatedDir) .set('@docs', docsDir) .set('@pages', pagesDir) .set('@build', outDir) @@ -75,7 +78,7 @@ module.exports = function createBaseConfig(props, isServer) { mdRule .use('markdown-loader') .loader(mdLoader) - .options({siteConfig, siteDir, docsDir}); + .options({siteConfig, versionedDir, translatedDir, docsDir, sourceToLink}); const cssRule = config.module.rule('css').test(/\.css$/); if (isProd) { @@ -110,12 +113,12 @@ module.exports = function createBaseConfig(props, isServer) { warnings: false, compress: false, ecma: 6, - mangle: true, + mangle: true }, sourceMap: true }) ]); } - + return config; }; diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index 6939e6030c..335a6c59ca 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -3,13 +3,58 @@ const fm = require('front-matter'); module.exports = function(fileString) { const options = getOptions(this); - const {siteConfig, siteDir, docsDir } = options; + const { + siteConfig, + versionedDir, + docsDir, + translatedDir, + sourceToLink + } = options; - /* - Process the markdown file content, including replacing all relative markdown links - */ - const {body: content = ''} = fm(fileString); - + /* Extract content of markdown (without frontmatter) */ + const {body} = fm(fileString); + + /* Determine whether this file is in @docs, @versioned_docs or @translated_docs */ + let dirAlias; + if (this.resourcePath.startsWith(translatedDir)) { + dirAlias = '@translated_docs'; + } else if (this.resourcePath.startsWith(versionedDir)) { + dirAlias = '@versioned_docs'; + } else if (this.resourcePath.startsWith(docsDir)) { + dirAlias = '@docs'; + } + + /* Replace internal markdown linking (except in fenced blocks) */ + let content = body; + if (dirAlias) { + let fencedBlock = false; + const lines = body.split('\n').map(line => { + if (line.trim().startsWith('```')) { + fencedBlock = !fencedBlock; + } + if (fencedBlock) return line; + + let modifiedLine = line; + const mdLinks = []; + const mdRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g; + let match = mdRegex.exec(content); + while (match !== null) { + mdLinks.push(match[1]); + match = mdRegex.exec(content); + } + mdLinks.forEach(mdLink => { + const source = `${dirAlias}/${mdLink}`; + const permalink = sourceToLink[source]; + if (permalink) { + modifiedLine = modifiedLine.replace(mdLink, permalink); + } + }); + return modifiedLine; + }); + content = lines.join('\n'); + } + + /* Return a React component */ return ( `import React from 'react';\n` + `import Markdown from '@theme/Markdown'\n` + From e9f2fabde12322bb777c106119e4ae71b7ce6506 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 22:10:19 +0800 Subject: [PATCH 121/135] chore: rename data -> metadata for consistency --- lib/core/App.js | 7 ++++--- lib/load/index.js | 18 +++++++++--------- lib/load/pages.js | 4 ++-- lib/load/routes.js | 6 +++--- lib/theme/Layout/index.js | 6 +++--- lib/webpack/server.js | 6 +++--- test/load/docs/index.test.js | 16 ++++++++-------- test/load/pages.test.js | 12 ++++++------ 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/lib/core/App.js b/lib/core/App.js index c0b92a8b44..3302a86ec3 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -1,8 +1,9 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line -import docsData from '@generated/docsData'; // eslint-disable-line -import pagesData from '@generated/pagesData'; // eslint-disable-line +import docsMetadata from '@generated/docsMetadata'; // eslint-disable-line +import pagesMetadata from '@generated/pagesMetadata'; // eslint-disable-line import siteConfig from '@site/siteConfig'; //eslint-disable-line -export default () => renderRoutes(routes, {docsData, pagesData, siteConfig}); +export default () => + renderRoutes(routes, {docsMetadata, pagesMetadata, siteConfig}); diff --git a/lib/load/index.js b/lib/load/index.js index 651975008e..7c986f7c3e 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -20,24 +20,24 @@ module.exports = async function load(siteDir) { '..', siteConfig.customDocsPath || 'docs' ); - const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); + const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); await generate( - 'docsData.js', - `export default ${JSON.stringify(docsData, null, 2)};` + 'docsMetadata.js', + `export default ${JSON.stringify(docsMetadata, null, 2)};` ); /* Create source to permalink mapping */ const sourceToLink = {}; - Object.values(docsData).forEach(({source, permalink}) => { + Object.values(docsMetadata).forEach(({source, permalink}) => { sourceToLink[source] = permalink; }); // pages const pagesDir = path.resolve(siteDir, 'pages'); - const pagesData = await loadPages(pagesDir); + const pagesMetadata = await loadPages(pagesDir); await generate( - 'pagesData.js', - `export default ${JSON.stringify(pagesData, null, 2)};` + 'pagesMetadata.js', + `export default ${JSON.stringify(pagesMetadata, null, 2)};` ); // resolve outDir @@ -54,10 +54,10 @@ module.exports = async function load(siteDir) { siteConfig, siteDir, docsDir, - docsData, + docsMetadata, env, pagesDir, - pagesData, + pagesMetadata, outDir, themePath, baseUrl, diff --git a/lib/load/pages.js b/lib/load/pages.js index 7278754164..e0e373647a 100644 --- a/lib/load/pages.js +++ b/lib/load/pages.js @@ -6,13 +6,13 @@ async function loadPages(pagesDir) { cwd: pagesDir }); - const pagesData = await Promise.all( + const pagesMetadata = await Promise.all( pagesFiles.map(async source => ({ path: encodePath(fileToPath(source)), source })) ); - return pagesData; + return pagesMetadata; } module.exports = loadPages; diff --git a/lib/load/routes.js b/lib/load/routes.js index d615960652..a3476c5327 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,4 +1,4 @@ -async function genRoutesConfig({docsData = {}, pagesData = []}) { +async function genRoutesConfig({docsMetadata = {}, pagesMetadata = []}) { function genDocsRoute(metadata) { const {permalink, source} = metadata; return ` @@ -38,7 +38,7 @@ async function genRoutesConfig({docsData = {}, pagesData = []}) { component: NotFound }`; - const docsRoutes = Object.values(docsData) + const docsRoutes = Object.values(docsMetadata) .map(genDocsRoute) .join(','); @@ -48,7 +48,7 @@ async function genRoutesConfig({docsData = {}, pagesData = []}) { `import Loading from '@theme/Loading';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + - `const routes = [${docsRoutes},${pagesData + `const routes = [${docsRoutes},${pagesMetadata .map(genPagesRoute) .join(',')}${notFoundRoute}\n];\n` + `export default routes;\n` diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index dd3fbffc78..e3e29ac8ad 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -5,11 +5,11 @@ import styles from './styles.css'; /* eslint-disable react/prefer-stateless-function */ export default class Layout extends React.Component { render() { - const {children, pagesData, docsData = {}, location} = this.props; - const docsLinks = Object.values(docsData).map(data => ({ + const {children, pagesMetadata, docsMetadata = {}, location} = this.props; + const docsLinks = Object.values(docsMetadata).map(data => ({ path: `${data.permalink}` })); - const routeLinks = [...pagesData, ...docsLinks].map( + const routeLinks = [...pagesMetadata, ...docsLinks].map( data => data.path !== location.pathname && (
  • diff --git a/lib/webpack/server.js b/lib/webpack/server.js index 85dec57c62..cbdf7bb744 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -14,13 +14,13 @@ module.exports = function createServerConfig(props) { // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) config.output.globalObject('this'); - const {siteConfig, docsData, pagesData} = props; + const {siteConfig, docsMetadata, pagesMetadata} = props; // static site generator webpack plugin - const docsLinks = Object.values(docsData).map(data => ({ + const docsLinks = Object.values(docsMetadata).map(data => ({ path: `${data.permalink}` })); - const paths = [...docsLinks, ...pagesData].map(data => data.path); + const paths = [...docsLinks, ...pagesMetadata].map(data => data.path); config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', diff --git a/test/load/docs/index.test.js b/test/load/docs/index.test.js index a2fb6e47a7..c90ebb4beb 100644 --- a/test/load/docs/index.test.js +++ b/test/load/docs/index.test.js @@ -5,28 +5,28 @@ describe('loadDocs', () => { test('simple website', async () => { const props = await loadSetup('simple'); const {siteDir, docsDir, env, siteConfig} = props; - const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsData).toMatchSnapshot(); + const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadata).toMatchSnapshot(); }); test('versioned website', async () => { const props = await loadSetup('versioned'); const {siteDir, docsDir, env, siteConfig} = props; - const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsData).toMatchSnapshot(); + const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadata).toMatchSnapshot(); }); test('versioned & translated website', async () => { const props = await loadSetup('transversioned'); const {siteDir, docsDir, env, siteConfig} = props; - const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsData).toMatchSnapshot(); + const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadata).toMatchSnapshot(); }); test('translated website', async () => { const props = await loadSetup('translated'); const {siteDir, docsDir, env, siteConfig} = props; - const docsData = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsData).toMatchSnapshot(); + const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadata).toMatchSnapshot(); }); }); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index d73bdcb57b..90a01c22b7 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -4,9 +4,9 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - const pagesData = await loadPages(pagesDir); - pagesData.sort((a, b) => a.path > b.path); // because it was unordered - expect(pagesData).toEqual([ + const pagesMetadata = await loadPages(pagesDir); + pagesMetadata.sort((a, b) => a.path > b.path); // because it was unordered + expect(pagesMetadata).toEqual([ { path: '/', source: 'index.js' @@ -24,12 +24,12 @@ describe('loadPages', () => { source: 'foo/index.js' } ]); - expect(pagesData).not.toBeNull(); + expect(pagesMetadata).not.toBeNull(); }); test('invalid pages', async () => { const nonExistingDir = path.join(__dirname, '__fixtures__', 'nonExisting'); - const pagesData = await loadPages(nonExistingDir); - expect(pagesData).toEqual([]); + const pagesMetadata = await loadPages(nonExistingDir); + expect(pagesMetadata).toEqual([]); }); }); From c0194a1f53fa1ff738838ef841a3c8241c571f7c Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 23:19:47 +0800 Subject: [PATCH 122/135] fix: markdown linking for translated & versioned docs --- lib/load/index.js | 16 ++-- lib/webpack/base.js | 10 ++- lib/webpack/loader/markdown.js | 35 ++++++--- test/__fixtures__/docs/hello.md | 14 ++++ .../translated_docs/ko/foo/bar.md | 66 +++++++++++++++++ .../translated_docs/ko/foo/baz.md | 74 +++++++++++++++++++ .../translated_docs/ko/hello.md | 54 ++++++++++++++ .../translated_docs/ko/version-1.0.0/hello.md | 14 ++++ .../translated_docs/ko/version-1.0.1/hello.md | 14 ++++ .../versioned_docs/version-1.0.0/hello.md | 14 ++++ .../versioned_docs/version-1.0.1/hello.md | 14 ++++ 11 files changed, 306 insertions(+), 19 deletions(-) create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md create mode 100644 test/__fixtures__/transversioned-site/translated_docs/ko/hello.md diff --git a/lib/load/index.js b/lib/load/index.js index 7c986f7c3e..e7c91d005f 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -27,10 +27,16 @@ module.exports = async function load(siteDir) { ); /* Create source to permalink mapping */ - const sourceToLink = {}; - Object.values(docsMetadata).forEach(({source, permalink}) => { - sourceToLink[source] = permalink; - }); + const sourceToMetadata = {}; + Object.values(docsMetadata).forEach( + ({source, version, permalink, language}) => { + sourceToMetadata[source] = { + version, + permalink, + language + }; + } + ); // pages const pagesDir = path.resolve(siteDir, 'pages'); @@ -61,7 +67,7 @@ module.exports = async function load(siteDir) { outDir, themePath, baseUrl, - sourceToLink, + sourceToMetadata, versionedDir, translatedDir }; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 9913fe9a31..9a135a45fc 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -13,7 +13,7 @@ module.exports = function createBaseConfig(props, isServer) { docsDir, pagesDir, siteDir, - sourceToLink, + sourceToMetadata, versionedDir, translatedDir, baseUrl @@ -78,7 +78,13 @@ module.exports = function createBaseConfig(props, isServer) { mdRule .use('markdown-loader') .loader(mdLoader) - .options({siteConfig, versionedDir, translatedDir, docsDir, sourceToLink}); + .options({ + siteConfig, + versionedDir, + translatedDir, + docsDir, + sourceToMetadata + }); const cssRule = config.module.rule('css').test(/\.css$/); if (isProd) { diff --git a/lib/webpack/loader/markdown.js b/lib/webpack/loader/markdown.js index 335a6c59ca..e5893299a6 100644 --- a/lib/webpack/loader/markdown.js +++ b/lib/webpack/loader/markdown.js @@ -8,25 +8,36 @@ module.exports = function(fileString) { versionedDir, docsDir, translatedDir, - sourceToLink + sourceToMetadata } = options; /* Extract content of markdown (without frontmatter) */ const {body} = fm(fileString); - /* Determine whether this file is in @docs, @versioned_docs or @translated_docs */ - let dirAlias; - if (this.resourcePath.startsWith(translatedDir)) { - dirAlias = '@translated_docs'; - } else if (this.resourcePath.startsWith(versionedDir)) { - dirAlias = '@versioned_docs'; - } else if (this.resourcePath.startsWith(docsDir)) { - dirAlias = '@docs'; + /* Determine the source dir. e.g: @docs, @translated_docs/ko and @versioned_docs/version-1.0.0 */ + let sourceDir; + let thisSource = this.resourcePath; + if (thisSource.startsWith(translatedDir)) { + thisSource = thisSource.replace(translatedDir, '@translated_docs'); + const {language, version} = sourceToMetadata[thisSource] || {}; + if (language && version && version !== 'next') { + sourceDir = `@translated_docs/${language}/version-${version}`; + } else if (language && (!version || version === 'next')) { + sourceDir = `@translated_docs/${language}`; + } + } else if (thisSource.startsWith(versionedDir)) { + thisSource = thisSource.replace(versionedDir, '@versioned_docs'); + const {version} = sourceToMetadata[thisSource] || {}; + if (version) { + sourceDir = `@versioned_docs/version-${version}`; + } + } else if (thisSource.startsWith(docsDir)) { + sourceDir = `@docs`; } /* Replace internal markdown linking (except in fenced blocks) */ let content = body; - if (dirAlias) { + if (sourceDir) { let fencedBlock = false; const lines = body.split('\n').map(line => { if (line.trim().startsWith('```')) { @@ -43,8 +54,8 @@ module.exports = function(fileString) { match = mdRegex.exec(content); } mdLinks.forEach(mdLink => { - const source = `${dirAlias}/${mdLink}`; - const permalink = sourceToLink[source]; + const targetSource = `${sourceDir}/${mdLink}`; + const {permalink} = sourceToMetadata[targetSource] || {}; if (permalink) { modifiedLine = modifiedLine.replace(mdLink, permalink); } diff --git a/test/__fixtures__/docs/hello.md b/test/__fixtures__/docs/hello.md index a392b2ca54..ab550d7363 100644 --- a/test/__fixtures__/docs/hello.md +++ b/test/__fixtures__/docs/hello.md @@ -5,6 +5,20 @@ title: Hello, World ! Hi, Endilie here :) +## Relative links + +Replace this +[foo](foo/bar.md) + +Can't replace this +[file](file.md) + +Do not replace below + +``` +[hello](hello.md) +``` + ## Blockquotes > Blockquotes can also be nested... diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md b/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md new file mode 100644 index 0000000000..a1b031cb23 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md @@ -0,0 +1,66 @@ +--- +id: bar +title: Bar +--- + +# Remarkable + +> Remarkable로 실시간 편집을 경험하십시오! + +깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다. + +*** + +# h1 제목 +## h2 제목 +### h3 제목 +#### h4 헤딩 +##### h5 제목 +###### h6 제목 + + +## 수평 규칙 + +___ + +*** + +*** + + +## 활자체 대체 + +입력기 옵션을 사용하면 결과를 볼 수 있습니다. + +(p) (P) + - (r) (t) + +테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! .... + +!!!!!! ???? ,, + +놀라운 - 굉장한 + +"Smartypants, 큰 따옴표" + +'Smartypants, 작은 따옴표' + + +## 강조 + +** 이것은 굵은 글씨입니다 ** + +__ 이것은 굵은 글씨입니다 __ + +* 이탤릭체 텍스트 * + +_ 이탤릭체 텍스트 _ + +~~ 삭제 된 텍스트 ~~ + +위 첨자 : 19 ^ th ^ + +아래 첨자 : H ~ 2 ~ O + +++ 삽입 된 텍스트 ++ + +== 표시된 텍스트 == \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md b/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md new file mode 100644 index 0000000000..c078572ef4 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md @@ -0,0 +1,74 @@ +--- +id: baz +title: baz +--- + +## 이미지 + +링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다. + +! [Alt text] [id] + +나중에 URL 위치를 정의하는 문서에서 참조로 : + +[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat" + +## 링크 + +[링크 텍스트] (http://dev.nodeca.com) + +[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!") + +자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정) + + + +## 각주 + +각주 1 링크 [^ 첫 번째]. + +각주 2 링크 [^ 초]. + +인라인 각주 ^ [인라인 각주의 텍스트] 정의. + +중복 된 각주 참조 [^ 초]. + +[^ first] : 각주 **는 마크 업을 가질 수 있습니다 ** + +    및 여러 단락. + +[^ 초] : 각주 텍스트. + + +## 정의 목록 + +1 학기 + +정의 1 +게으른 연속. + +* 인라인 마크 업과 함께 2 학기 * + +: 정의 2 + +        {일부 코드, 정의 2의 일부} + +    정의의 세 번째 단락 2. + +_ 컴팩트 스타일 : _ + +1 학기 +  ~ 정의 1 + +2 학기 +  ~ 정의 2a +  ~ 정의 2b + + +## 약어 + +이것은 HTML 약어입니다. + +그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다. + +* [HTML] : 하이퍼 텍스트 마크 업 언어 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md b/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md new file mode 100644 index 0000000000..cb2afd1888 --- /dev/null +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md @@ -0,0 +1,54 @@ +--- +id: hello +title: Hello, World ! +--- + +안녕하세요, 여기 엔 틸리에 :) + +## 상대 링크 + +이것 바꾸기 +[foo](foo/bar.md) + +이것을 대체 할 수 없습니다. +[파일] (file.md) + +아래를 교체하지 마십시오. + +``` +[hello] (hello.md) +``` + +## Blockquotes + +> Blockquotes는 또한 중첩 될 수 있습니다 ... +>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ... +>>> ... 또는 화살표 사이에 공백이 있어야합니다. + + +## 목록 + +정렬되지 않은 + ++`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다. ++ 하위 목록은 2 칸을 들여서 만들어집니다 : +   - 마커 문자 변경으로 새로운 목록 시작 : +     * AC tristique libero volutpat at +     + Preisium nisl aliquet에 대한 + 시설 +     - Nulla volutpat aliquam velit ++ 매우 쉽습니다! + +주문 됨 + +1. Lorem ipsum dolor sit amet +2. 컨소시엄 adipiscing 엘리트 +3. massa에서의 정수 lorem + + +1. 일련 번호를 사용할 수 있습니다 ... +1. ... 또는 모든 숫자를 '1'로 유지하십시오. + +오프셋을 사용하여 번호 매기기 시작 : + +57. foo +1. 막대기 \ No newline at end of file diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md index 5075f44119..5148b6723f 100644 --- a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md @@ -5,6 +5,20 @@ title: Hello, World ! 안녕하세요, 여기 엔 틸리에 :) +## 상대 링크 + +이것 바꾸기 +[foo](foo/bar.md) + +이것을 대체 할 수 없습니다. +[파일] (file.md) + +아래를 교체하지 마십시오. + +``` +[hello] (hello.md) +``` + ## Blockquotes > Blockquotes는 또한 중첩 될 수 있습니다 ... diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md index 80ef3933a4..f76f93aabb 100644 --- a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md +++ b/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md @@ -5,6 +5,20 @@ title: Hello, World ! 안녕하세요, 여기 엔 틸리에 :) +## 상대 링크 + +이것 바꾸기 +[foo](foo/bar.md) + +이것을 대체 할 수 없습니다. +[파일] (file.md) + +아래를 교체하지 마십시오. + +``` +[hello] (hello.md) +``` + ## Blockquotes > Blockquotes는 또한 중첩 될 수 있습니다 ... diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md index ef91d00826..56665f5b2e 100644 --- a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md @@ -5,6 +5,20 @@ title: Hello, World ! Hi, Endilie here :) +## Relative links + +Replace this +[foo](foo/bar.md) + +Can't replace this +[file](file.md) + +Do not replace below + +``` +[hello](hello.md) +``` + ## Blockquotes > Blockquotes can also be nested... diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md index 3a81461691..9e6725f688 100644 --- a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md +++ b/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md @@ -5,6 +5,20 @@ title: Hello, World ! Hi, Endilie here :) +## Relative links + +Replace this +[foo](foo/bar.md) + +Can't replace this +[file](file.md) + +Do not replace below + +``` +[hello](hello.md) +``` + ## Blockquotes > Blockquotes can also be nested... From 11b0d15238e51cee5460fbb078dc7715a7f78cc4 Mon Sep 17 00:00:00 2001 From: endiliey Date: Fri, 14 Sep 2018 23:49:03 +0800 Subject: [PATCH 123/135] feat: pass loaded siteConfig as props for React component --- lib/commands/start.js | 2 +- lib/core/App.js | 2 +- lib/load/config.js | 11 +++++++++++ lib/load/docs/metadata.js | 2 +- lib/load/index.js | 14 +++++++------- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/commands/start.js b/lib/commands/start.js index a95d15d050..bc4a350520 100644 --- a/lib/commands/start.js +++ b/lib/commands/start.js @@ -39,7 +39,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { console.error(chalk.red(err.stack)); }); }; - const docsRelativeDir = props.siteConfig.customDocsPath || 'docs'; + const docsRelativeDir = props.siteConfig.customDocsPath; const fsWatcher = chokidar.watch( [`../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', 'siteConfig.js'], { diff --git a/lib/core/App.js b/lib/core/App.js index 3302a86ec3..c2970e4d3f 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -3,7 +3,7 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line import docsMetadata from '@generated/docsMetadata'; // eslint-disable-line import pagesMetadata from '@generated/pagesMetadata'; // eslint-disable-line -import siteConfig from '@site/siteConfig'; //eslint-disable-line +import siteConfig from '@generated/siteConfig'; //eslint-disable-line export default () => renderRoutes(routes, {docsMetadata, pagesMetadata, siteConfig}); diff --git a/lib/load/config.js b/lib/load/config.js index 1ef863e889..890b92ddfb 100644 --- a/lib/load/config.js +++ b/lib/load/config.js @@ -35,6 +35,17 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { ); } + /* Fill default value */ + const defaultConfig = { + customDocsPath: 'docs', + docsUrl: 'docs' + }; + Object.keys(defaultConfig).forEach(field => { + if (!config[field]) { + config[field] = defaultConfig[field]; + } + }); + /* User's own array of custom fields, e.g: if they want to include some field so they can access it later from `props.siteConfig` diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index 165f343140..a3e1d9bb46 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -118,7 +118,7 @@ module.exports = async function processMetadata( } /* Build the permalink */ - const {baseUrl, docsUrl = 'docs'} = siteConfig; + const {baseUrl, docsUrl} = siteConfig; /* if user has own custom permalink defined in frontmatter diff --git a/lib/load/index.js b/lib/load/index.js index e7c91d005f..691e1a1232 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -10,23 +10,23 @@ const genRoutesConfig = require('./routes'); module.exports = async function load(siteDir) { // @tested - siteConfig const siteConfig = loadConfig(siteDir); + await generate( + 'siteConfig.js', + `export default ${JSON.stringify(siteConfig, null, 2)};` + ); // @tested - env const env = loadEnv({siteDir, siteConfig}); // docs - const docsDir = path.resolve( - siteDir, - '..', - siteConfig.customDocsPath || 'docs' - ); + const docsDir = path.resolve(siteDir, '..', siteConfig.customDocsPath); const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); await generate( 'docsMetadata.js', `export default ${JSON.stringify(docsMetadata, null, 2)};` ); - /* Create source to permalink mapping */ + /* Create source to metadata mapping */ const sourceToMetadata = {}; Object.values(docsMetadata).forEach( ({source, version, permalink, language}) => { @@ -52,7 +52,7 @@ module.exports = async function load(siteDir) { // resolve the theme const themePath = loadTheme(siteDir); - const baseUrl = siteConfig.baseUrl || '/'; + const {baseUrl} = siteConfig; const versionedDir = path.join(siteDir, 'versioned_docs'); const translatedDir = path.join(siteDir, 'translated_docs'); From 318ea5fbb59f3cde83e25a35b1e730152cc983c3 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 00:25:12 +0800 Subject: [PATCH 124/135] feat: add next/prev button for docs according to sidebar --- lib/load/docs/metadata.js | 6 +++--- lib/theme/Docs/index.js | 28 ++++++++++++++++++++++++++-- website/sidebars.json | 13 +++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 website/sidebars.json diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index a3e1d9bb46..a4d13d1eb3 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -144,14 +144,14 @@ module.exports = async function processMetadata( metadata.id = `version-${version}-${metadata.id}`; } + /* save localized id before adding language on it*/ + metadata.localized_id = metadata.id; + /* if language */ if (language) { metadata.id = `${language}-${metadata.id}`; } - /* localize id */ - metadata.localized_id = metadata.id; - /* Determine order */ const id = metadata.localized_id; if (order[id]) { diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index e74b8586b3..32670ad907 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -6,13 +6,37 @@ import Layout from '@theme/Layout'; // eslint-disable-line export default class Docs extends React.Component { render() { - const {route, siteConfig, metadata} = this.props; + const {route, siteConfig, docsMetadata, metadata} = this.props; return ( {(metadata && metadata.title) || siteConfig.title} -
    {this.props.children}
    +
    + {metadata.previous && + docsMetadata[metadata.previous] && ( + + + {metadata.previous_title} + + )} +
    +
    + {metadata.next && + docsMetadata[metadata.next] && ( + + {metadata.next_title} + + + )} +
    +
    + {this.props.children} +
    ); } diff --git a/website/sidebars.json b/website/sidebars.json new file mode 100644 index 0000000000..0c61221124 --- /dev/null +++ b/website/sidebars.json @@ -0,0 +1,13 @@ +{ + "docs": { + "Foo": [ + "foo/bar", + "foo/baz" + ], + "Endi": [ + "docusaurus", + "highlight", + "hello" + ] + } +} From e071788f68b3e16a73a3f11921903fbc41645583 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 00:29:33 +0800 Subject: [PATCH 125/135] refactor: use from react-router for next/prev link --- lib/theme/Docs/index.js | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index 32670ad907..0be8baf454 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -1,5 +1,6 @@ /* eslint-disable */ import React from 'react'; +import {Link} from 'react-router-dom'; import Helmet from 'react-helmet'; import styles from './styles.css'; import Layout from '@theme/Layout'; // eslint-disable-line @@ -12,31 +13,23 @@ export default class Docs extends React.Component { {(metadata && metadata.title) || siteConfig.title} -
    +
    {metadata.previous && docsMetadata[metadata.previous] && ( - - - {metadata.previous_title} - + + ← {metadata.previous_title} + )}
    -
    +
    {metadata.next && docsMetadata[metadata.next] && ( - - {metadata.next_title} - - + + {metadata.next_title} → + )}
    -
    - {this.props.children} -
    +
    {this.props.children}
    ); } From 6b112812470c44615960df259f38aea7deeb168c Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 01:06:35 +0800 Subject: [PATCH 126/135] test: metadata test for next/prev from sidebars --- test/__fixtures__/simple-site/sidebars.json | 7 +- .../translated-site/sidebars.json | 11 + .../__fixtures__/versioned-site/sidebars.json | 7 +- .../docs/__snapshots__/index.test.js.snap | 253 ++++++++++++++++-- test/load/docs/metadata.test.js | 12 +- 5 files changed, 255 insertions(+), 35 deletions(-) create mode 100644 test/__fixtures__/translated-site/sidebars.json diff --git a/test/__fixtures__/simple-site/sidebars.json b/test/__fixtures__/simple-site/sidebars.json index 49667e47b5..24d61b49c7 100644 --- a/test/__fixtures__/simple-site/sidebars.json +++ b/test/__fixtures__/simple-site/sidebars.json @@ -1,10 +1,11 @@ { "docs": { - "Getting Started": [ - "installation" + "Test": [ + "foo/bar", + "foo/baz" ], "Guides": [ - "blog" + "hello" ] } } diff --git a/test/__fixtures__/translated-site/sidebars.json b/test/__fixtures__/translated-site/sidebars.json new file mode 100644 index 0000000000..24d61b49c7 --- /dev/null +++ b/test/__fixtures__/translated-site/sidebars.json @@ -0,0 +1,11 @@ +{ + "docs": { + "Test": [ + "foo/bar", + "foo/baz" + ], + "Guides": [ + "hello" + ] + } +} diff --git a/test/__fixtures__/versioned-site/sidebars.json b/test/__fixtures__/versioned-site/sidebars.json index 49667e47b5..24d61b49c7 100644 --- a/test/__fixtures__/versioned-site/sidebars.json +++ b/test/__fixtures__/versioned-site/sidebars.json @@ -1,10 +1,11 @@ { "docs": { - "Getting Started": [ - "installation" + "Test": [ + "foo/bar", + "foo/baz" ], "Guides": [ - "blog" + "hello" ] } } diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/test/load/docs/__snapshots__/index.test.js.snap index 4bbac6aa0c..77ec92bbcc 100644 --- a/test/load/docs/__snapshots__/index.test.js.snap +++ b/test/load/docs/__snapshots__/index.test.js.snap @@ -3,28 +3,46 @@ exports[`loadDocs simple website 1`] = ` Object { "foo/bar": Object { + "category": "Test", "id": "foo/bar", "language": undefined, "localized_id": "foo/bar", + "next": "foo/baz", + "next_id": "foo/baz", + "next_title": "baz", "permalink": "/docs/foo/bar", + "sidebar": "docs", "source": "@docs/foo/bar.md", "title": "Bar", "version": undefined, }, "foo/baz": Object { + "category": "Test", "id": "foo/baz", "language": undefined, "localized_id": "foo/baz", + "next": "hello", + "next_id": "hello", + "next_title": "Hello, World !", "permalink": "/docs/foo/baz", + "previous": "foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", "source": "@docs/foo/baz.md", "title": "baz", "version": undefined, }, "hello": Object { + "category": "Guides", "id": "hello", "language": undefined, "localized_id": "hello", "permalink": "/docs/hello", + "previous": "foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", "source": "@docs/hello.md", "title": "Hello, World !", "version": undefined, @@ -44,28 +62,46 @@ Object { exports[`loadDocs translated website 1`] = ` Object { "en-foo/bar": Object { + "category": "Test", "id": "en-foo/bar", "language": "en", - "localized_id": "en-foo/bar", + "localized_id": "foo/bar", + "next": "en-foo/baz", + "next_id": "foo/baz", + "next_title": "baz", "permalink": "/docs/en/foo/bar", + "sidebar": "docs", "source": "@docs/foo/bar.md", "title": "Bar", "version": undefined, }, "en-foo/baz": Object { + "category": "Test", "id": "en-foo/baz", "language": "en", - "localized_id": "en-foo/baz", + "localized_id": "foo/baz", + "next": "en-hello", + "next_id": "hello", + "next_title": "Hello, World !", "permalink": "/docs/en/foo/baz", + "previous": "en-foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", "source": "@docs/foo/baz.md", "title": "baz", "version": undefined, }, "en-hello": Object { + "category": "Guides", "id": "en-hello", "language": "en", - "localized_id": "en-hello", + "localized_id": "hello", "permalink": "/docs/en/hello", + "previous": "en-foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", "source": "@docs/hello.md", "title": "Hello, World !", "version": undefined, @@ -73,35 +109,53 @@ Object { "en-permalink": Object { "id": "en-permalink", "language": "en", - "localized_id": "en-permalink", + "localized_id": "permalink", "permalink": "/docs/en/endiliey/permalink", "source": "@docs/permalink.md", "title": "Permalink", "version": undefined, }, "ko-foo/bar": Object { + "category": "Test", "id": "ko-foo/bar", "language": "ko", - "localized_id": "ko-foo/bar", + "localized_id": "foo/bar", + "next": "ko-foo/baz", + "next_id": "foo/baz", + "next_title": "baz", "permalink": "/docs/ko/foo/bar", + "sidebar": "docs", "source": "@translated_docs/ko/foo/bar.md", "title": "Bar", "version": undefined, }, "ko-foo/baz": Object { + "category": "Test", "id": "ko-foo/baz", "language": "ko", - "localized_id": "ko-foo/baz", + "localized_id": "foo/baz", + "next": "ko-hello", + "next_id": "hello", + "next_title": "Hello, World !", "permalink": "/docs/ko/foo/baz", + "previous": "ko-foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", "source": "@translated_docs/ko/foo/baz.md", "title": "baz", "version": undefined, }, "ko-hello": Object { + "category": "Guides", "id": "ko-hello", "language": "ko", - "localized_id": "ko-hello", + "localized_id": "hello", "permalink": "/docs/ko/hello", + "previous": "ko-foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", "source": "@translated_docs/ko/hello.md", "title": "Hello, World !", "version": undefined, @@ -112,28 +166,46 @@ Object { exports[`loadDocs versioned & translated website 1`] = ` Object { "en-foo/bar": Object { + "category": "Test", "id": "en-foo/bar", "language": "en", - "localized_id": "en-foo/bar", + "localized_id": "foo/bar", + "next": "en-foo/baz", + "next_id": "foo/baz", + "next_title": "baz", "permalink": "/docs/en/next/foo/bar", + "sidebar": "docs", "source": "@docs/foo/bar.md", "title": "Bar", "version": "next", }, "en-foo/baz": Object { + "category": "Test", "id": "en-foo/baz", "language": "en", - "localized_id": "en-foo/baz", + "localized_id": "foo/baz", + "next": "en-hello", + "next_id": "hello", + "next_title": "Hello, World !", "permalink": "/docs/en/next/foo/baz", + "previous": "en-foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", "source": "@docs/foo/baz.md", "title": "baz", "version": "next", }, "en-hello": Object { + "category": "Guides", "id": "en-hello", "language": "en", - "localized_id": "en-hello", + "localized_id": "hello", "permalink": "/docs/en/next/hello", + "previous": "en-foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", "source": "@docs/hello.md", "title": "Hello, World !", "version": "next", @@ -141,116 +213,233 @@ Object { "en-permalink": Object { "id": "en-permalink", "language": "en", - "localized_id": "en-permalink", + "localized_id": "permalink", "permalink": "/docs/en/next/endiliey/permalink", "source": "@docs/permalink.md", "title": "Permalink", "version": "next", }, "en-version-1.0.0-foo/bar": Object { + "category": "Test", "id": "en-version-1.0.0-foo/bar", "language": "en", - "localized_id": "en-version-1.0.0-foo/bar", + "localized_id": "version-1.0.0-foo/bar", + "next": "en-version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "Baz", "permalink": "/docs/en/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", "source": "@versioned_docs/version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, "en-version-1.0.0-foo/baz": Object { + "category": "Test", "id": "en-version-1.0.0-foo/baz", "language": "en", - "localized_id": "en-version-1.0.0-foo/baz", + "localized_id": "version-1.0.0-foo/baz", + "next": "en-version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", "permalink": "/docs/en/1.0.0/foo/baz", + "previous": "en-version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", "source": "@versioned_docs/version-1.0.0/foo/baz.md", "title": "Baz", "version": "1.0.0", }, "en-version-1.0.0-hello": Object { + "category": "Guides", "id": "en-version-1.0.0-hello", "language": "en", - "localized_id": "en-version-1.0.0-hello", + "localized_id": "version-1.0.0-hello", "permalink": "/docs/en/1.0.0/hello", + "previous": "en-version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.0-docs", "source": "@versioned_docs/version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, "en-version-1.0.1-foo/bar": Object { + "category": "Test", "id": "en-version-1.0.1-foo/bar", "language": "en", - "localized_id": "en-version-1.0.1-foo/bar", + "localized_id": "version-1.0.1-foo/bar", + "next": "en-version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "Baz", "permalink": "/docs/en/foo/bar", + "sidebar": "version-1.0.1-docs", "source": "@versioned_docs/version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, "en-version-1.0.1-foo/baz": Object { + "category": "Test", "id": "en-version-1.0.1-foo/baz", "language": "en", - "localized_id": "en-version-1.0.1-foo/baz", + "localized_id": "version-1.0.1-foo/baz", + "next": "en-version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", "permalink": "/docs/en/foo/baz", + "previous": "en-version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", "source": "@versioned_docs/version-1.0.1/foo/baz.md", "title": "Baz", "version": "1.0.1", }, "en-version-1.0.1-hello": Object { + "category": "Guides", "id": "en-version-1.0.1-hello", "language": "en", - "localized_id": "en-version-1.0.1-hello", + "localized_id": "version-1.0.1-hello", "permalink": "/docs/en/hello", + "previous": "en-version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "Baz", + "sidebar": "version-1.0.1-docs", "source": "@versioned_docs/version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", }, + "ko-foo/bar": Object { + "category": "Test", + "id": "ko-foo/bar", + "language": "ko", + "localized_id": "foo/bar", + "next": "ko-foo/baz", + "next_id": "foo/baz", + "next_title": "baz", + "permalink": "/docs/ko/next/foo/bar", + "sidebar": "docs", + "source": "@translated_docs/ko/foo/bar.md", + "title": "Bar", + "version": "next", + }, + "ko-foo/baz": Object { + "category": "Test", + "id": "ko-foo/baz", + "language": "ko", + "localized_id": "foo/baz", + "next": "ko-hello", + "next_id": "hello", + "next_title": "Hello, World !", + "permalink": "/docs/ko/next/foo/baz", + "previous": "ko-foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", + "source": "@translated_docs/ko/foo/baz.md", + "title": "baz", + "version": "next", + }, + "ko-hello": Object { + "category": "Guides", + "id": "ko-hello", + "language": "ko", + "localized_id": "hello", + "permalink": "/docs/ko/next/hello", + "previous": "ko-foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", + "source": "@translated_docs/ko/hello.md", + "title": "Hello, World !", + "version": "next", + }, "ko-version-1.0.0-foo/bar": Object { + "category": "Test", "id": "ko-version-1.0.0-foo/bar", "language": "ko", - "localized_id": "ko-version-1.0.0-foo/bar", + "localized_id": "version-1.0.0-foo/bar", + "next": "ko-version-1.0.0-foo/baz", + "next_id": "version-1.0.0-foo/baz", + "next_title": "baz", "permalink": "/docs/ko/1.0.0/foo/bar", + "sidebar": "version-1.0.0-docs", "source": "@translated_docs/ko/version-1.0.0/foo/bar.md", "title": "Bar", "version": "1.0.0", }, "ko-version-1.0.0-foo/baz": Object { + "category": "Test", "id": "ko-version-1.0.0-foo/baz", "language": "ko", - "localized_id": "ko-version-1.0.0-foo/baz", + "localized_id": "version-1.0.0-foo/baz", + "next": "ko-version-1.0.0-hello", + "next_id": "version-1.0.0-hello", + "next_title": "Hello, World !", "permalink": "/docs/ko/1.0.0/foo/baz", + "previous": "ko-version-1.0.0-foo/bar", + "previous_id": "version-1.0.0-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.0-docs", "source": "@translated_docs/ko/version-1.0.0/foo/baz.md", "title": "baz", "version": "1.0.0", }, "ko-version-1.0.0-hello": Object { + "category": "Guides", "id": "ko-version-1.0.0-hello", "language": "ko", - "localized_id": "ko-version-1.0.0-hello", + "localized_id": "version-1.0.0-hello", "permalink": "/docs/ko/1.0.0/hello", + "previous": "ko-version-1.0.0-foo/baz", + "previous_id": "version-1.0.0-foo/baz", + "previous_title": "baz", + "sidebar": "version-1.0.0-docs", "source": "@translated_docs/ko/version-1.0.0/hello.md", "title": "Hello, World !", "version": "1.0.0", }, "ko-version-1.0.1-foo/bar": Object { + "category": "Test", "id": "ko-version-1.0.1-foo/bar", "language": "ko", - "localized_id": "ko-version-1.0.1-foo/bar", + "localized_id": "version-1.0.1-foo/bar", + "next": "ko-version-1.0.1-foo/baz", + "next_id": "version-1.0.1-foo/baz", + "next_title": "baz", "permalink": "/docs/ko/foo/bar", + "sidebar": "version-1.0.1-docs", "source": "@translated_docs/ko/version-1.0.1/foo/bar.md", "title": "Bar", "version": "1.0.1", }, "ko-version-1.0.1-foo/baz": Object { + "category": "Test", "id": "ko-version-1.0.1-foo/baz", "language": "ko", - "localized_id": "ko-version-1.0.1-foo/baz", + "localized_id": "version-1.0.1-foo/baz", + "next": "ko-version-1.0.1-hello", + "next_id": "version-1.0.1-hello", + "next_title": "Hello, World !", "permalink": "/docs/ko/foo/baz", + "previous": "ko-version-1.0.1-foo/bar", + "previous_id": "version-1.0.1-foo/bar", + "previous_title": "Bar", + "sidebar": "version-1.0.1-docs", "source": "@translated_docs/ko/version-1.0.1/foo/baz.md", "title": "baz", "version": "1.0.1", }, "ko-version-1.0.1-hello": Object { + "category": "Guides", "id": "ko-version-1.0.1-hello", "language": "ko", - "localized_id": "ko-version-1.0.1-hello", + "localized_id": "version-1.0.1-hello", "permalink": "/docs/ko/hello", + "previous": "ko-version-1.0.1-foo/baz", + "previous_id": "version-1.0.1-foo/baz", + "previous_title": "baz", + "sidebar": "version-1.0.1-docs", "source": "@translated_docs/ko/version-1.0.1/hello.md", "title": "Hello, World !", "version": "1.0.1", @@ -261,28 +450,46 @@ Object { exports[`loadDocs versioned website 1`] = ` Object { "foo/bar": Object { + "category": "Test", "id": "foo/bar", "language": undefined, "localized_id": "foo/bar", + "next": "foo/baz", + "next_id": "foo/baz", + "next_title": "baz", "permalink": "/docs/next/foo/bar", + "sidebar": "docs", "source": "@docs/foo/bar.md", "title": "Bar", "version": "next", }, "foo/baz": Object { + "category": "Test", "id": "foo/baz", "language": undefined, "localized_id": "foo/baz", + "next": "hello", + "next_id": "hello", + "next_title": "Hello, World !", "permalink": "/docs/next/foo/baz", + "previous": "foo/bar", + "previous_id": "foo/bar", + "previous_title": "Bar", + "sidebar": "docs", "source": "@docs/foo/baz.md", "title": "baz", "version": "next", }, "hello": Object { + "category": "Guides", "id": "hello", "language": undefined, "localized_id": "hello", "permalink": "/docs/next/hello", + "previous": "foo/baz", + "previous_id": "foo/baz", + "previous_title": "baz", + "sidebar": "docs", "source": "@docs/hello.md", "title": "Hello, World !", "version": "next", diff --git a/test/load/docs/metadata.test.js b/test/load/docs/metadata.test.js index 1791bac108..bf2a96640a 100644 --- a/test/load/docs/metadata.test.js +++ b/test/load/docs/metadata.test.js @@ -89,7 +89,7 @@ describe('processMetadata', () => { expect(dataA).toEqual({ id: 'ko-version-1.0.0-foo/bar', language: 'ko', - localized_id: 'ko-version-1.0.0-foo/bar', + localized_id: 'version-1.0.0-foo/bar', permalink: '/docs/ko/1.0.0/foo/bar', source: '@translated_docs/ko/version-1.0.0/foo/bar.md', title: 'Bar', @@ -98,7 +98,7 @@ describe('processMetadata', () => { expect(dataB).toEqual({ id: 'ko-version-1.0.0-hello', language: 'ko', - localized_id: 'ko-version-1.0.0-hello', + localized_id: 'version-1.0.0-hello', permalink: '/docs/ko/1.0.0/hello', source: '@translated_docs/ko/version-1.0.0/hello.md', title: 'Hello, World !', @@ -107,7 +107,7 @@ describe('processMetadata', () => { expect(dataC).toEqual({ id: 'ko-version-1.0.1-foo/bar', language: 'ko', - localized_id: 'ko-version-1.0.1-foo/bar', + localized_id: 'version-1.0.1-foo/bar', permalink: '/docs/ko/foo/bar', source: '@translated_docs/ko/version-1.0.1/foo/bar.md', title: 'Bar', @@ -116,7 +116,7 @@ describe('processMetadata', () => { expect(dataD).toEqual({ id: 'ko-version-1.0.1-hello', language: 'ko', - localized_id: 'ko-version-1.0.1-hello', + localized_id: 'version-1.0.1-hello', permalink: '/docs/ko/hello', source: '@translated_docs/ko/version-1.0.1/hello.md', title: 'Hello, World !', @@ -135,7 +135,7 @@ describe('processMetadata', () => { expect(dataA).toEqual({ id: 'ko-foo/bar', language: 'ko', - localized_id: 'ko-foo/bar', + localized_id: 'foo/bar', permalink: '/docs/ko/foo/bar', source: '@translated_docs/ko/foo/bar.md', title: 'Bar', @@ -144,7 +144,7 @@ describe('processMetadata', () => { expect(dataB).toEqual({ id: 'ko-hello', language: 'ko', - localized_id: 'ko-hello', + localized_id: 'hello', permalink: '/docs/ko/hello', source: '@translated_docs/ko/hello.md', title: 'Hello, World !', From 5eab627340705780100edc541054d65a8219fab3 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 15:01:03 +0800 Subject: [PATCH 127/135] feat: avoid flash Of Loading component --- lib/theme/Loading.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/theme/Loading.js b/lib/theme/Loading.js index 692fe085f9..8363912ef3 100644 --- a/lib/theme/Loading.js +++ b/lib/theme/Loading.js @@ -11,5 +11,8 @@ export default props => {
    ); } - return
    Loading...
    ; + if (props.pastDelay) { + return
    Loading...
    ; + } + return null; }; From c132c7445fbd74c0df1aba5a39c13350cec646dd Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 15:15:30 +0800 Subject: [PATCH 128/135] chore: naming consistency --- lib/core/App.js | 6 +++--- lib/load/docs/index.js | 31 +++++++++++++++++-------------- lib/load/index.js | 19 ++++++++++--------- lib/load/pages.js | 4 ++-- lib/load/routes.js | 6 +++--- lib/theme/Docs/index.js | 10 +++++----- lib/theme/Layout/index.js | 6 +++--- lib/webpack/server.js | 6 +++--- test/load/config.test.js | 2 ++ test/load/docs/index.test.js | 16 ++++++++-------- test/load/pages.test.js | 12 ++++++------ 11 files changed, 62 insertions(+), 56 deletions(-) diff --git a/lib/core/App.js b/lib/core/App.js index c2970e4d3f..1de9335253 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -1,9 +1,9 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line -import docsMetadata from '@generated/docsMetadata'; // eslint-disable-line -import pagesMetadata from '@generated/pagesMetadata'; // eslint-disable-line +import docsMetadatas from '@generated/docsMetadatas'; // eslint-disable-line +import pagesMetadatas from '@generated/pagesMetadatas'; // eslint-disable-line import siteConfig from '@generated/siteConfig'; //eslint-disable-line export default () => - renderRoutes(routes, {docsMetadata, pagesMetadata, siteConfig}); + renderRoutes(routes, {docsMetadatas, pagesMetadatas, siteConfig}); diff --git a/lib/load/docs/index.js b/lib/load/docs/index.js index 6c4fcef18a..9cd9ad496d 100644 --- a/lib/load/docs/index.js +++ b/lib/load/docs/index.js @@ -7,10 +7,10 @@ const {getSubFolder, idx} = require('../utils'); async function loadDocs({siteDir, docsDir, env, siteConfig}) { // @tested - load all sidebars including versioned sidebars - const allSidebars = loadSidebars({siteDir, env}); + const docsSidebars = loadSidebars({siteDir, env}); // @tested - build the docs ordering such as next, previous, category and sidebar - const order = createOrder(allSidebars); + const order = createOrder(docsSidebars); /* Settle versions & translations from environment */ const translationEnabled = idx(env, ['translation', 'enabled']); @@ -24,7 +24,7 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { (versioningEnabled && idx(env, ['versioning', 'versions'])) || []; /* Prepare metadata container */ - const metadatas = {}; + const docsMetadatas = {}; /* metadata for default docs files */ const docsFiles = await globby(['**/*.md'], { @@ -49,7 +49,7 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { order, siteConfig ); - metadatas[metadata.id] = metadata; + docsMetadatas[metadata.id] = metadata; }) ); @@ -80,7 +80,7 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { order, siteConfig ); - metadatas[metadata.id] = metadata; + docsMetadatas[metadata.id] = metadata; }) ); @@ -98,27 +98,30 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { order, siteConfig ); - metadatas[metadata.id] = metadata; + docsMetadatas[metadata.id] = metadata; }) ); /* Get the titles of the previous and next ids so that we can use them */ - Object.keys(metadatas).forEach(currentID => { - const previousID = idx(metadatas, [currentID, 'previous']); + Object.keys(docsMetadatas).forEach(currentID => { + const previousID = idx(docsMetadatas, [currentID, 'previous']); if (previousID) { - const previousTitle = idx(metadatas, [previousID, 'title']); - metadatas[currentID].previous_title = previousTitle || 'Previous'; + const previousTitle = idx(docsMetadatas, [previousID, 'title']); + docsMetadatas[currentID].previous_title = previousTitle || 'Previous'; } - const nextID = idx(metadatas, [currentID, 'next']); + const nextID = idx(docsMetadatas, [currentID, 'next']); if (nextID) { - const nextTitle = idx(metadatas, [nextID, 'title']); - metadatas[currentID].next_title = nextTitle || 'Next'; + const nextTitle = idx(docsMetadatas, [nextID, 'title']); + docsMetadatas[currentID].next_title = nextTitle || 'Next'; } }); - return metadatas; + return { + docsSidebars, + docsMetadatas + }; } module.exports = loadDocs; diff --git a/lib/load/index.js b/lib/load/index.js index 691e1a1232..9be4bbc8a2 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -20,15 +20,15 @@ module.exports = async function load(siteDir) { // docs const docsDir = path.resolve(siteDir, '..', siteConfig.customDocsPath); - const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); + const {docsMetadatas, docsSidebars} = await loadDocs({siteDir, docsDir, env, siteConfig}); await generate( - 'docsMetadata.js', - `export default ${JSON.stringify(docsMetadata, null, 2)};` + 'docsMetadatas.js', + `export default ${JSON.stringify(docsMetadatas, null, 2)};` ); /* Create source to metadata mapping */ const sourceToMetadata = {}; - Object.values(docsMetadata).forEach( + Object.values(docsMetadatas).forEach( ({source, version, permalink, language}) => { sourceToMetadata[source] = { version, @@ -40,10 +40,10 @@ module.exports = async function load(siteDir) { // pages const pagesDir = path.resolve(siteDir, 'pages'); - const pagesMetadata = await loadPages(pagesDir); + const pagesMetadatas = await loadPages(pagesDir); await generate( - 'pagesMetadata.js', - `export default ${JSON.stringify(pagesMetadata, null, 2)};` + 'pagesMetadatas.js', + `export default ${JSON.stringify(pagesMetadatas, null, 2)};` ); // resolve outDir @@ -60,10 +60,11 @@ module.exports = async function load(siteDir) { siteConfig, siteDir, docsDir, - docsMetadata, + docsMetadatas, + docsSidebars, env, pagesDir, - pagesMetadata, + pagesMetadatas, outDir, themePath, baseUrl, diff --git a/lib/load/pages.js b/lib/load/pages.js index e0e373647a..5c1b46f6da 100644 --- a/lib/load/pages.js +++ b/lib/load/pages.js @@ -6,13 +6,13 @@ async function loadPages(pagesDir) { cwd: pagesDir }); - const pagesMetadata = await Promise.all( + const pagesMetadatas = await Promise.all( pagesFiles.map(async source => ({ path: encodePath(fileToPath(source)), source })) ); - return pagesMetadata; + return pagesMetadatas; } module.exports = loadPages; diff --git a/lib/load/routes.js b/lib/load/routes.js index a3476c5327..2c63a747d3 100644 --- a/lib/load/routes.js +++ b/lib/load/routes.js @@ -1,4 +1,4 @@ -async function genRoutesConfig({docsMetadata = {}, pagesMetadata = []}) { +async function genRoutesConfig({docsMetadatas = {}, pagesMetadatas = []}) { function genDocsRoute(metadata) { const {permalink, source} = metadata; return ` @@ -38,7 +38,7 @@ async function genRoutesConfig({docsMetadata = {}, pagesMetadata = []}) { component: NotFound }`; - const docsRoutes = Object.values(docsMetadata) + const docsRoutes = Object.values(docsMetadatas) .map(genDocsRoute) .join(','); @@ -48,7 +48,7 @@ async function genRoutesConfig({docsMetadata = {}, pagesMetadata = []}) { `import Loading from '@theme/Loading';\n` + `import Docs from '@theme/Docs';\n` + `import NotFound from '@theme/NotFound';\n` + - `const routes = [${docsRoutes},${pagesMetadata + `const routes = [${docsRoutes},${pagesMetadatas .map(genPagesRoute) .join(',')}${notFoundRoute}\n];\n` + `export default routes;\n` diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index 0be8baf454..6b9a4eec8a 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -7,7 +7,7 @@ import Layout from '@theme/Layout'; // eslint-disable-line export default class Docs extends React.Component { render() { - const {route, siteConfig, docsMetadata, metadata} = this.props; + const {route, siteConfig, docsMetadatas, metadata} = this.props; return ( @@ -15,16 +15,16 @@ export default class Docs extends React.Component {
    {metadata.previous && - docsMetadata[metadata.previous] && ( - + docsMetadatas[metadata.previous] && ( + ← {metadata.previous_title} )}
    {metadata.next && - docsMetadata[metadata.next] && ( - + docsMetadatas[metadata.next] && ( + {metadata.next_title} → )} diff --git a/lib/theme/Layout/index.js b/lib/theme/Layout/index.js index e3e29ac8ad..d96ab6d10c 100644 --- a/lib/theme/Layout/index.js +++ b/lib/theme/Layout/index.js @@ -5,11 +5,11 @@ import styles from './styles.css'; /* eslint-disable react/prefer-stateless-function */ export default class Layout extends React.Component { render() { - const {children, pagesMetadata, docsMetadata = {}, location} = this.props; - const docsLinks = Object.values(docsMetadata).map(data => ({ + const {children, pagesMetadatas, docsMetadatas = {}, location} = this.props; + const docsLinks = Object.values(docsMetadatas).map(data => ({ path: `${data.permalink}` })); - const routeLinks = [...pagesMetadata, ...docsLinks].map( + const routeLinks = [...pagesMetadatas, ...docsLinks].map( data => data.path !== location.pathname && (
  • diff --git a/lib/webpack/server.js b/lib/webpack/server.js index cbdf7bb744..f6aacc1c22 100644 --- a/lib/webpack/server.js +++ b/lib/webpack/server.js @@ -14,13 +14,13 @@ module.exports = function createServerConfig(props) { // Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522) config.output.globalObject('this'); - const {siteConfig, docsMetadata, pagesMetadata} = props; + const {siteConfig, docsMetadatas, pagesMetadatas} = props; // static site generator webpack plugin - const docsLinks = Object.values(docsMetadata).map(data => ({ + const docsLinks = Object.values(docsMetadatas).map(data => ({ path: `${data.permalink}` })); - const paths = [...docsLinks, ...pagesMetadata].map(data => data.path); + const paths = [...docsLinks, ...pagesMetadatas].map(data => data.path); config.plugin('siteGenerator').use(staticSiteGenerator, [ { entry: 'main', diff --git a/test/load/config.test.js b/test/load/config.test.js index 41d1ed0fc6..0288acfe39 100644 --- a/test/load/config.test.js +++ b/test/load/config.test.js @@ -8,6 +8,8 @@ describe('loadConfig', () => { expect(config).toEqual({ baseUrl: '/', organizationName: 'endiliey', + customDocsPath: 'docs', + docsUrl: 'docs', projectName: 'hello', tagline: 'Hello World', title: 'Hello' diff --git a/test/load/docs/index.test.js b/test/load/docs/index.test.js index c90ebb4beb..cca7155674 100644 --- a/test/load/docs/index.test.js +++ b/test/load/docs/index.test.js @@ -5,28 +5,28 @@ describe('loadDocs', () => { test('simple website', async () => { const props = await loadSetup('simple'); const {siteDir, docsDir, env, siteConfig} = props; - const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsMetadata).toMatchSnapshot(); + const {docsMetadatas} = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadatas).toMatchSnapshot(); }); test('versioned website', async () => { const props = await loadSetup('versioned'); const {siteDir, docsDir, env, siteConfig} = props; - const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsMetadata).toMatchSnapshot(); + const {docsMetadatas} = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadatas).toMatchSnapshot(); }); test('versioned & translated website', async () => { const props = await loadSetup('transversioned'); const {siteDir, docsDir, env, siteConfig} = props; - const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsMetadata).toMatchSnapshot(); + const {docsMetadatas} = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadatas).toMatchSnapshot(); }); test('translated website', async () => { const props = await loadSetup('translated'); const {siteDir, docsDir, env, siteConfig} = props; - const docsMetadata = await loadDocs({siteDir, docsDir, env, siteConfig}); - expect(docsMetadata).toMatchSnapshot(); + const {docsMetadatas} = await loadDocs({siteDir, docsDir, env, siteConfig}); + expect(docsMetadatas).toMatchSnapshot(); }); }); diff --git a/test/load/pages.test.js b/test/load/pages.test.js index 90a01c22b7..4f43cf2779 100644 --- a/test/load/pages.test.js +++ b/test/load/pages.test.js @@ -4,9 +4,9 @@ import path from 'path'; describe('loadPages', () => { test('valid pages', async () => { const pagesDir = path.join(__dirname, '__fixtures__', 'simple-pages'); - const pagesMetadata = await loadPages(pagesDir); - pagesMetadata.sort((a, b) => a.path > b.path); // because it was unordered - expect(pagesMetadata).toEqual([ + const pagesMetadatas = await loadPages(pagesDir); + pagesMetadatas.sort((a, b) => a.path > b.path); // because it was unordered + expect(pagesMetadatas).toEqual([ { path: '/', source: 'index.js' @@ -24,12 +24,12 @@ describe('loadPages', () => { source: 'foo/index.js' } ]); - expect(pagesMetadata).not.toBeNull(); + expect(pagesMetadatas).not.toBeNull(); }); test('invalid pages', async () => { const nonExistingDir = path.join(__dirname, '__fixtures__', 'nonExisting'); - const pagesMetadata = await loadPages(nonExistingDir); - expect(pagesMetadata).toEqual([]); + const pagesMetadatas = await loadPages(nonExistingDir); + expect(pagesMetadatas).toEqual([]); }); }); From 85f0fd69c0e060a3306acda31a2ec9e2b307b6f0 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sat, 15 Sep 2018 16:19:48 +0800 Subject: [PATCH 129/135] feat: add docs sidebar --- lib/core/App.js | 8 ++++++- lib/load/docs/metadata.js | 2 +- lib/load/index.js | 11 ++++++++- lib/theme/Docs/index.js | 47 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/lib/core/App.js b/lib/core/App.js index 1de9335253..4fabf192dc 100644 --- a/lib/core/App.js +++ b/lib/core/App.js @@ -2,8 +2,14 @@ import {renderRoutes} from 'react-router-config'; import routes from '@generated/routes'; // eslint-disable-line import docsMetadatas from '@generated/docsMetadatas'; // eslint-disable-line +import docsSidebars from '@generated/docsSidebars'; // eslint-disable-line import pagesMetadatas from '@generated/pagesMetadatas'; // eslint-disable-line import siteConfig from '@generated/siteConfig'; //eslint-disable-line export default () => - renderRoutes(routes, {docsMetadatas, pagesMetadatas, siteConfig}); + renderRoutes(routes, { + docsMetadatas, + docsSidebars, + pagesMetadatas, + siteConfig + }); diff --git a/lib/load/docs/metadata.js b/lib/load/docs/metadata.js index a4d13d1eb3..9a8c2687dc 100644 --- a/lib/load/docs/metadata.js +++ b/lib/load/docs/metadata.js @@ -144,7 +144,7 @@ module.exports = async function processMetadata( metadata.id = `version-${version}-${metadata.id}`; } - /* save localized id before adding language on it*/ + /* save localized id before adding language on it */ metadata.localized_id = metadata.id; /* if language */ diff --git a/lib/load/index.js b/lib/load/index.js index 9be4bbc8a2..2dd0bd4ff3 100644 --- a/lib/load/index.js +++ b/lib/load/index.js @@ -20,11 +20,20 @@ module.exports = async function load(siteDir) { // docs const docsDir = path.resolve(siteDir, '..', siteConfig.customDocsPath); - const {docsMetadatas, docsSidebars} = await loadDocs({siteDir, docsDir, env, siteConfig}); + const {docsMetadatas, docsSidebars} = await loadDocs({ + siteDir, + docsDir, + env, + siteConfig + }); await generate( 'docsMetadatas.js', `export default ${JSON.stringify(docsMetadatas, null, 2)};` ); + await generate( + 'docsSidebars.js', + `export default ${JSON.stringify(docsSidebars, null, 2)};` + ); /* Create source to metadata mapping */ const sourceToMetadata = {}; diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index 6b9a4eec8a..db1b7da79e 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -6,13 +6,55 @@ import styles from './styles.css'; import Layout from '@theme/Layout'; // eslint-disable-line export default class Docs extends React.Component { + renderSidebar(metadata, docsSidebars, docsMetadatas) { + const {sidebar, language, id: thisID} = metadata; + if (!sidebar || !docsSidebars) { + return null; + } + const thisSidebar = docsSidebars[sidebar]; + return ( + thisSidebar && + Object.keys(thisSidebar).map(categoryName => { + return ( +
    +

    {categoryName}

    +
      + {thisSidebar[categoryName].map(rawLinkID => { + const linkID = (language ? `${language}-` : '') + rawLinkID; + const linkMetadata = docsMetadatas[linkID]; + const linkClassName = + linkID === thisID ? 'navListItemActive' : 'navListItem'; + return ( + linkMetadata && ( +
    • + + {linkMetadata.sidebar_label || linkMetadata.title} + +
    • + ) + ); + })} +
    +
    + ); + }) + ); + } + render() { - const {route, siteConfig, docsMetadatas, metadata} = this.props; + const { + route, + siteConfig, + docsMetadatas, + docsSidebars, + metadata + } = this.props; return ( {(metadata && metadata.title) || siteConfig.title} +
    {this.renderSidebar(metadata, docsSidebars, docsMetadatas)}
    {metadata.previous && docsMetadatas[metadata.previous] && ( @@ -20,8 +62,7 @@ export default class Docs extends React.Component { ← {metadata.previous_title} )} -
    -
    + {' ⚫️ '} {metadata.next && docsMetadatas[metadata.next] && ( From 15a810fee550ae92c2466552bdf7066d818a2c15 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 16 Sep 2018 01:40:56 +0800 Subject: [PATCH 130/135] chore: nits --- lib/load/docs/index.js | 4 +--- lib/theme/Docs/index.js | 17 ++++++++++------- lib/theme/Loading.js | 9 +-------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/load/docs/index.js b/lib/load/docs/index.js index 9cd9ad496d..aaaace5b51 100644 --- a/lib/load/docs/index.js +++ b/lib/load/docs/index.js @@ -102,9 +102,7 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { }) ); - /* - Get the titles of the previous and next ids so that we can use them - */ + /* Get the titles of the previous and next ids so that we can use them */ Object.keys(docsMetadatas).forEach(currentID => { const previousID = idx(docsMetadatas, [currentID, 'previous']); if (previousID) { diff --git a/lib/theme/Docs/index.js b/lib/theme/Docs/index.js index db1b7da79e..8d4217d37f 100644 --- a/lib/theme/Docs/index.js +++ b/lib/theme/Docs/index.js @@ -22,16 +22,19 @@ export default class Docs extends React.Component { {thisSidebar[categoryName].map(rawLinkID => { const linkID = (language ? `${language}-` : '') + rawLinkID; const linkMetadata = docsMetadatas[linkID]; + if (!linkMetadata) { + throw new Error( + `Improper sidebars.json file, document with id '${linkID}' not found.` + ); + } const linkClassName = linkID === thisID ? 'navListItemActive' : 'navListItem'; return ( - linkMetadata && ( -
  • - - {linkMetadata.sidebar_label || linkMetadata.title} - -
  • - ) +
  • + + {linkMetadata.sidebar_label || linkMetadata.title} + +
  • ); })} diff --git a/lib/theme/Loading.js b/lib/theme/Loading.js index 8363912ef3..44443ff411 100644 --- a/lib/theme/Loading.js +++ b/lib/theme/Loading.js @@ -2,14 +2,7 @@ import React from 'react'; export default props => { if (props.error) { - return ( -
    - Error!{' '} - -
    - ); + return
    Error 🔥🔥🔥
    ; } if (props.pastDelay) { return
    Loading...
    ; From 141d6558af30b2ff52ebc76a4f5b74b42e135dca Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 16 Sep 2018 12:55:19 +0800 Subject: [PATCH 131/135] refactor: only process translated & versioned if it is enabled --- lib/load/docs/index.js | 92 ++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/lib/load/docs/index.js b/lib/load/docs/index.js index aaaace5b51..fd7e6aa748 100644 --- a/lib/load/docs/index.js +++ b/lib/load/docs/index.js @@ -54,53 +54,57 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { ); /* metadata for non-default-language docs */ - const translatedDir = path.join(siteDir, 'translated_docs'); - const translatedFiles = await globby(['**/*.md'], { - cwd: translatedDir - }); - await Promise.all( - translatedFiles.map(async source => { - /* - Do not process disabled & default languages folder in `translated_docs` - e.g: 'translated_docs/ja/**' should not be processed if lang 'ja' is disabled - */ - const translatedFilePath = path.resolve(translatedDir, source); - const detectedLangTag = getSubFolder(translatedFilePath, translatedDir); - if ( - detectedLangTag === defaultLangTag || - !enabledLangTags.includes(detectedLangTag) - ) { - return; - } + if (translationEnabled) { + const translatedDir = path.join(siteDir, 'translated_docs'); + const translatedFiles = await globby(['**/*.md'], { + cwd: translatedDir + }); + await Promise.all( + translatedFiles.map(async source => { + /* + Do not process disabled & default languages folder in `translated_docs` + e.g: 'translated_docs/ja/**' should not be processed if lang 'ja' is disabled + */ + const translatedFilePath = path.resolve(translatedDir, source); + const detectedLangTag = getSubFolder(translatedFilePath, translatedDir); + if ( + detectedLangTag === defaultLangTag || + !enabledLangTags.includes(detectedLangTag) + ) { + return; + } - const metadata = await processMetadata( - source, - translatedDir, - env, - order, - siteConfig - ); - docsMetadatas[metadata.id] = metadata; - }) - ); + const metadata = await processMetadata( + source, + translatedDir, + env, + order, + siteConfig + ); + docsMetadatas[metadata.id] = metadata; + }) + ); + } /* metadata for versioned docs */ - const versionedDir = path.join(siteDir, 'versioned_docs'); - const versionedFiles = await globby(['**/*.md'], { - cwd: versionedDir - }); - await Promise.all( - versionedFiles.map(async source => { - const metadata = await processMetadata( - source, - versionedDir, - env, - order, - siteConfig - ); - docsMetadatas[metadata.id] = metadata; - }) - ); + if (versioningEnabled) { + const versionedDir = path.join(siteDir, 'versioned_docs'); + const versionedFiles = await globby(['**/*.md'], { + cwd: versionedDir + }); + await Promise.all( + versionedFiles.map(async source => { + const metadata = await processMetadata( + source, + versionedDir, + env, + order, + siteConfig + ); + docsMetadatas[metadata.id] = metadata; + }) + ); + } /* Get the titles of the previous and next ids so that we can use them */ Object.keys(docsMetadatas).forEach(currentID => { From dc7ef9684955946c948e0c8a27f56c0676b78aa6 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 16 Sep 2018 14:21:44 +0800 Subject: [PATCH 132/135] refactor: css extraction --- lib/webpack/base.js | 263 ++++++++++++++++++++++---------------------- 1 file changed, 133 insertions(+), 130 deletions(-) diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 9a135a45fc..df1363ca41 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -1,130 +1,133 @@ -const Config = require('webpack-chain'); -const CSSExtractPlugin = require('mini-css-extract-plugin'); -const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const path = require('path'); - -const mdLoader = require.resolve('./loader/markdown'); - -module.exports = function createBaseConfig(props, isServer) { - const { - siteConfig, - outDir, - themePath, - docsDir, - pagesDir, - siteDir, - sourceToMetadata, - versionedDir, - translatedDir, - baseUrl - } = props; - - const config = new Config(); - const isProd = process.env.NODE_ENV === 'production'; - - config - .mode(isProd ? 'production' : 'development') - .output.path(outDir) - .filename(isProd ? '[name].[chunkhash].js' : '[name].js') - .publicPath(isProd ? baseUrl : '/'); - - if (!isProd) { - config.devtool('cheap-module-eval-source-map'); - } - - config.resolve - .set('symlinks', true) - .alias.set('@theme', themePath) - .set('@site', siteDir) - .set('@versioned_docs', versionedDir) - .set('@translated_docs', translatedDir) - .set('@docs', docsDir) - .set('@pages', pagesDir) - .set('@build', outDir) - .set('@generated', path.resolve(__dirname, '../core/generated')) - .set('@core', path.resolve(__dirname, '../core')) - .end(); - - function applyBabel(rule) { - rule - .use('babel') - .loader('babel-loader') - .options({ - babelrc: false, - presets: ['env', 'react'], - plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import'] - }); - } - - const jsRule = config.module - .rule('js') - .test(/\.js$/) - .exclude.add(filepath => { - // Always transpile lib directory - if (filepath.startsWith(path.join(__dirname, '..'))) { - return false; - } - // Don't transpile node_modules - return /node_modules/.test(filepath); - }) - .end(); - - applyBabel(jsRule); - - const mdRule = config.module.rule('markdown').test(/\.md$/); - - applyBabel(mdRule); - - mdRule - .use('markdown-loader') - .loader(mdLoader) - .options({ - siteConfig, - versionedDir, - translatedDir, - docsDir, - sourceToMetadata - }); - - const cssRule = config.module.rule('css').test(/\.css$/); - if (isProd) { - cssRule.use('extract-css-loader').loader(CSSExtractPlugin.loader); - } else { - cssRule.use('style-loader').loader('style-loader'); - } - cssRule - .use('css-loader') - .loader('css-loader') - .options({ - modules: true, - importLoaders: 1, - localIdentName: `[local]_[hash:base64:8]`, - sourceMap: !isProd, - minimize: true - }); - - // mini-css-extract plugin - config.plugin('extract-css').use(CSSExtractPlugin, [ - { - filename: isProd ? '[name].[chunkhash].css' : '[name].css', - chunkFilename: isProd ? '[id].[chunkhash].css' : '[id].css' - } - ]); - - if (isProd) { - config.optimization.minimizer([ - new UglifyJsPlugin({ - cache: true, - uglifyOptions: { - warnings: false, - compress: false, - ecma: 6, - mangle: true - }, - sourceMap: true - }) - ]); - } - - return config; -}; +const Config = require('webpack-chain'); +const CSSExtractPlugin = require('mini-css-extract-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const path = require('path'); + +const mdLoader = require.resolve('./loader/markdown'); + +module.exports = function createBaseConfig(props, isServer) { + const { + siteConfig, + outDir, + themePath, + docsDir, + pagesDir, + siteDir, + sourceToMetadata, + versionedDir, + translatedDir, + baseUrl + } = props; + + const config = new Config(); + const isProd = process.env.NODE_ENV === 'production'; + + config + .mode(isProd ? 'production' : 'development') + .output.path(outDir) + .filename(isProd ? '[name].[chunkhash].js' : '[name].js') + .publicPath(isProd ? baseUrl : '/'); + + if (!isProd) { + config.devtool('cheap-module-eval-source-map'); + } + + config.resolve + .set('symlinks', true) + .alias.set('@theme', themePath) + .set('@site', siteDir) + .set('@versioned_docs', versionedDir) + .set('@translated_docs', translatedDir) + .set('@docs', docsDir) + .set('@pages', pagesDir) + .set('@build', outDir) + .set('@generated', path.resolve(__dirname, '../core/generated')) + .set('@core', path.resolve(__dirname, '../core')) + .end(); + + function applyBabel(rule) { + rule + .use('babel') + .loader('babel-loader') + .options({ + babelrc: false, + presets: ['env', 'react'], + plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import'] + }); + } + + const jsRule = config.module + .rule('js') + .test(/\.js$/) + .exclude.add(filepath => { + // Always transpile lib directory + if (filepath.startsWith(path.join(__dirname, '..'))) { + return false; + } + // Don't transpile node_modules + return /node_modules/.test(filepath); + }) + .end(); + + applyBabel(jsRule); + + const mdRule = config.module.rule('markdown').test(/\.md$/); + + applyBabel(mdRule); + + mdRule + .use('markdown-loader') + .loader(mdLoader) + .options({ + siteConfig, + versionedDir, + translatedDir, + docsDir, + sourceToMetadata + }); + + const cssRule = config.module.rule('css').test(/\.css$/); + if (!isServer) { + if (isProd) { + cssRule.use('extract-css-loader').loader(CSSExtractPlugin.loader); + } else { + cssRule.use('style-loader').loader('style-loader'); + } + } + + cssRule + .use('css-loader') + .loader(isServer ? 'css-loader/locals' : 'css-loader') + .options({ + modules: true, + importLoaders: 1, + localIdentName: `[local]_[hash:base64:8]`, + sourceMap: !isProd, + minimize: true + }); + + // mini-css-extract plugin + config.plugin('extract-css').use(CSSExtractPlugin, [ + { + filename: isProd ? '[name].[chunkhash].css' : '[name].css', + chunkFilename: isProd ? '[id].[chunkhash].css' : '[id].css' + } + ]); + + if (isProd) { + config.optimization.minimizer([ + new UglifyJsPlugin({ + cache: true, + uglifyOptions: { + warnings: false, + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]); + } + + return config; +}; From 45736200b057f437fa774d9f9885087d25b278cd Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 17 Sep 2018 11:16:07 +0800 Subject: [PATCH 133/135] v2: prepare to move --- LICENSE.md => v2/LICENSE.md | 0 README.md => v2/README.md | 0 {bin => v2/bin}/munseo.js | 0 {docs => v2/docs}/docusaurus.md | 0 {docs => v2/docs}/foo/bar.md | 0 {docs => v2/docs}/foo/baz.md | 0 {docs => v2/docs}/hello.md | 0 {docs => v2/docs}/highlight.md | 0 {lib => v2/lib}/commands/build.js | 0 {lib => v2/lib}/commands/eject.js | 0 {lib => v2/lib}/commands/init.js | 0 {lib => v2/lib}/commands/start.js | 0 {lib => v2/lib}/core/App.js | 0 {lib => v2/lib}/core/clientEntry.js | 0 {lib => v2/lib}/core/devTemplate.ejs | 0 {lib => v2/lib}/core/prerender.js | 0 {lib => v2/lib}/core/serverEntry.js | 0 {lib => v2/lib}/index.js | 0 {lib => v2/lib}/load/config.js | 0 {lib => v2/lib}/load/docs/index.js | 0 {lib => v2/lib}/load/docs/metadata.js | 0 {lib => v2/lib}/load/docs/order.js | 0 {lib => v2/lib}/load/docs/sidebars.js | 0 {lib => v2/lib}/load/env.js | 0 {lib => v2/lib}/load/index.js | 0 {lib => v2/lib}/load/pages.js | 0 {lib => v2/lib}/load/routes.js | 0 {lib => v2/lib}/load/theme.js | 0 {lib => v2/lib}/load/utils.js | 0 {lib => v2/lib}/theme/Docs/index.js | 0 {lib => v2/lib}/theme/Docs/styles.css | 0 {lib => v2/lib}/theme/Layout/index.js | 0 {lib => v2/lib}/theme/Layout/styles.css | 0 {lib => v2/lib}/theme/Loading.js | 0 {lib => v2/lib}/theme/Markdown/anchors.js | 0 {lib => v2/lib}/theme/Markdown/highlight.js | 0 {lib => v2/lib}/theme/Markdown/index.js | 0 {lib => v2/lib}/theme/Markdown/toSlug.js | 0 {lib => v2/lib}/theme/NotFound.js | 0 {lib => v2/lib}/webpack/base.js | 0 {lib => v2/lib}/webpack/client.js | 0 {lib => v2/lib}/webpack/loader/markdown.js | 0 {lib => v2/lib}/webpack/server.js | 0 {lib => v2/lib}/webpack/utils.js | 0 package.json => v2/package.json | 0 .../test}/__fixtures__/custom-site/pages/bar/baz.js | 0 .../test}/__fixtures__/custom-site/pages/foo.js | 0 .../__fixtures__/custom-site/pages/foo/index.js | 0 .../test}/__fixtures__/custom-site/pages/index.js | 0 .../test}/__fixtures__/custom-site/siteConfig.js | 0 {test => v2/test}/__fixtures__/docs/foo/bar.md | 0 {test => v2/test}/__fixtures__/docs/foo/baz.md | 0 {test => v2/test}/__fixtures__/docs/hello.md | 0 {test => v2/test}/__fixtures__/docs/permalink.md | 0 .../__fixtures__/simple-site/pages/hello/world.js | 0 .../test}/__fixtures__/simple-site/pages/index.js | 0 .../test}/__fixtures__/simple-site/sidebars.json | 0 .../test}/__fixtures__/simple-site/siteConfig.js | 0 .../__fixtures__/simple-site/static/css/basic.css | 0 .../__fixtures__/simple-site/static/img/sakura.png | Bin .../simple-site/static/img/slash-introducing.png | Bin .../test}/__fixtures__/translated-site/languages.js | 0 .../translated-site/pages/hello/world.js | 0 .../__fixtures__/translated-site/pages/index.js | 0 .../__fixtures__/translated-site/sidebars.json | 0 .../__fixtures__/translated-site/siteConfig.js | 0 .../translated-site/static/css/basic.css | 0 .../translated-site/static/img/sakura.png | Bin .../static/img/slash-introducing.png | Bin .../translated-site/translated_docs/ko/foo/bar.md | 0 .../translated-site/translated_docs/ko/foo/baz.md | 0 .../translated-site/translated_docs/ko/hello.md | 0 .../__fixtures__/transversioned-site/languages.js | 0 .../transversioned-site/pages/hello/world.js | 0 .../__fixtures__/transversioned-site/pages/index.js | 0 .../__fixtures__/transversioned-site/sidebars.json | 0 .../__fixtures__/transversioned-site/siteConfig.js | 0 .../transversioned-site/static/css/basic.css | 0 .../transversioned-site/static/img/sakura.png | Bin .../static/img/slash-introducing.png | Bin .../translated_docs/ko/foo/bar.md | 0 .../translated_docs/ko/foo/baz.md | 0 .../transversioned-site/translated_docs/ko/hello.md | 0 .../translated_docs/ko/version-1.0.0/foo/bar.md | 0 .../translated_docs/ko/version-1.0.0/foo/baz.md | 0 .../translated_docs/ko/version-1.0.0/hello.md | 0 .../translated_docs/ko/version-1.0.1/foo/bar.md | 0 .../translated_docs/ko/version-1.0.1/foo/baz.md | 0 .../translated_docs/ko/version-1.0.1/hello.md | 0 .../versioned_docs/version-1.0.0/foo/bar.md | 0 .../versioned_docs/version-1.0.0/foo/baz.md | 0 .../versioned_docs/version-1.0.0/hello.md | 0 .../versioned_docs/version-1.0.1/foo/bar.md | 0 .../versioned_docs/version-1.0.1/foo/baz.md | 0 .../versioned_docs/version-1.0.1/hello.md | 0 .../versioned_sidebars/version-1.0.0-sidebars.json | 0 .../versioned_sidebars/version-1.0.1-sidebars.json | 0 .../__fixtures__/transversioned-site/versions.json | 0 .../versioned-site/pages/hello/world.js | 0 .../__fixtures__/versioned-site/pages/index.js | 0 .../test}/__fixtures__/versioned-site/sidebars.json | 0 .../test}/__fixtures__/versioned-site/siteConfig.js | 0 .../versioned-site/static/css/basic.css | 0 .../versioned-site/static/img/sakura.png | Bin .../versioned-site/static/img/slash-introducing.png | Bin .../versioned_docs/version-1.0.0/foo/bar.md | 0 .../versioned_docs/version-1.0.0/foo/baz.md | 0 .../versioned_docs/version-1.0.0/hello.md | 0 .../versioned_docs/version-1.0.1/foo/bar.md | 0 .../versioned_docs/version-1.0.1/foo/baz.md | 0 .../versioned_docs/version-1.0.1/hello.md | 0 .../versioned_sidebars/version-1.0.0-sidebars.json | 0 .../versioned_sidebars/version-1.0.1-sidebars.json | 0 .../test}/__fixtures__/versioned-site/versions.json | 0 {test => v2/test}/jest.config.js | 0 .../test}/load/__fixtures__/bad-site/languages.js | 0 .../test}/load/__fixtures__/bad-site/siteConfig.js | 0 .../test}/load/__fixtures__/simple-pages/bar/baz.js | 0 .../test}/load/__fixtures__/simple-pages/foo.js | 0 .../load/__fixtures__/simple-pages/foo/index.js | 0 .../test}/load/__fixtures__/simple-pages/index.js | 0 .../load/__fixtures__/simple-site/sidebars.json | 0 .../load/__fixtures__/simple-site/siteConfig.js | 0 .../load/__fixtures__/translated-site/languages.js | 0 .../load/__fixtures__/translated-site/siteConfig.js | 0 .../__fixtures__/transversioned-site/languages.js | 0 .../__fixtures__/transversioned-site/sidebars.json | 0 .../__fixtures__/transversioned-site/siteConfig.js | 0 .../versioned_sidebars/version-1.0.0-sidebars.json | 0 .../versioned_sidebars/version-1.0.1-sidebars.json | 0 .../__fixtures__/transversioned-site/versions.json | 0 .../load/__fixtures__/versioned-site/sidebars.json | 0 .../load/__fixtures__/versioned-site/siteConfig.js | 0 .../versioned_sidebars/version-1.0.0-sidebars.json | 0 .../versioned_sidebars/version-1.0.1-sidebars.json | 0 .../load/__fixtures__/versioned-site/versions.json | 0 .../load/__fixtures__/wrong-site/siteConfig.js | 0 .../test}/load/__snapshots__/env.test.js.snap | 0 {test => v2/test}/load/config.test.js | 0 .../load/docs/__snapshots__/index.test.js.snap | 0 .../load/docs/__snapshots__/sidebars.test.js.snap | 0 {test => v2/test}/load/docs/index.test.js | 0 {test => v2/test}/load/docs/metadata.test.js | 0 {test => v2/test}/load/docs/order.test.js | 0 {test => v2/test}/load/docs/sidebars.test.js | 0 {test => v2/test}/load/env.test.js | 0 {test => v2/test}/load/pages.test.js | 0 {test => v2/test}/load/routes.test.js | 0 {test => v2/test}/load/utils.test.js | 0 {test => v2/test}/loadSetup.js | 0 {test => v2/test}/webpack/base.test.js | 0 {test => v2/test}/webpack/client.test.js | 0 {test => v2/test}/webpack/server.test.js | 0 {test => v2/test}/webpack/utils.test.js | 0 {website => v2/website}/blog/2018-08-08-sakura.md | 0 .../website}/components/Tictactoe/board.js | 0 .../website}/components/Tictactoe/index.js | 0 .../website}/components/Tictactoe/square.js | 0 .../website}/components/Tictactoe/styles.css | 0 {website => v2/website}/components/Todo/TodoItem.js | 0 {website => v2/website}/components/Todo/TodoList.js | 0 {website => v2/website}/components/Todo/index.js | 0 {website => v2/website}/package.json | 0 {website => v2/website}/pages/index.js | 0 {website => v2/website}/pages/tictactoe.js | 0 {website => v2/website}/pages/youtube.js | 0 {website => v2/website}/sidebars.json | 0 {website => v2/website}/siteConfig.js | 0 {website => v2/website}/static/css/basic.css | 0 {website => v2/website}/static/img/sakura.png | Bin .../website}/static/img/slash-introducing.png | Bin yarn.lock => v2/yarn.lock | 0 172 files changed, 0 insertions(+), 0 deletions(-) rename LICENSE.md => v2/LICENSE.md (100%) rename README.md => v2/README.md (100%) rename {bin => v2/bin}/munseo.js (100%) rename {docs => v2/docs}/docusaurus.md (100%) rename {docs => v2/docs}/foo/bar.md (100%) rename {docs => v2/docs}/foo/baz.md (100%) rename {docs => v2/docs}/hello.md (100%) rename {docs => v2/docs}/highlight.md (100%) rename {lib => v2/lib}/commands/build.js (100%) rename {lib => v2/lib}/commands/eject.js (100%) rename {lib => v2/lib}/commands/init.js (100%) rename {lib => v2/lib}/commands/start.js (100%) rename {lib => v2/lib}/core/App.js (100%) rename {lib => v2/lib}/core/clientEntry.js (100%) rename {lib => v2/lib}/core/devTemplate.ejs (100%) rename {lib => v2/lib}/core/prerender.js (100%) rename {lib => v2/lib}/core/serverEntry.js (100%) rename {lib => v2/lib}/index.js (100%) rename {lib => v2/lib}/load/config.js (100%) rename {lib => v2/lib}/load/docs/index.js (100%) rename {lib => v2/lib}/load/docs/metadata.js (100%) rename {lib => v2/lib}/load/docs/order.js (100%) rename {lib => v2/lib}/load/docs/sidebars.js (100%) rename {lib => v2/lib}/load/env.js (100%) rename {lib => v2/lib}/load/index.js (100%) rename {lib => v2/lib}/load/pages.js (100%) rename {lib => v2/lib}/load/routes.js (100%) rename {lib => v2/lib}/load/theme.js (100%) rename {lib => v2/lib}/load/utils.js (100%) rename {lib => v2/lib}/theme/Docs/index.js (100%) rename {lib => v2/lib}/theme/Docs/styles.css (100%) rename {lib => v2/lib}/theme/Layout/index.js (100%) rename {lib => v2/lib}/theme/Layout/styles.css (100%) rename {lib => v2/lib}/theme/Loading.js (100%) rename {lib => v2/lib}/theme/Markdown/anchors.js (100%) rename {lib => v2/lib}/theme/Markdown/highlight.js (100%) rename {lib => v2/lib}/theme/Markdown/index.js (100%) rename {lib => v2/lib}/theme/Markdown/toSlug.js (100%) rename {lib => v2/lib}/theme/NotFound.js (100%) rename {lib => v2/lib}/webpack/base.js (100%) rename {lib => v2/lib}/webpack/client.js (100%) rename {lib => v2/lib}/webpack/loader/markdown.js (100%) rename {lib => v2/lib}/webpack/server.js (100%) rename {lib => v2/lib}/webpack/utils.js (100%) rename package.json => v2/package.json (100%) rename {test => v2/test}/__fixtures__/custom-site/pages/bar/baz.js (100%) rename {test => v2/test}/__fixtures__/custom-site/pages/foo.js (100%) rename {test => v2/test}/__fixtures__/custom-site/pages/foo/index.js (100%) rename {test => v2/test}/__fixtures__/custom-site/pages/index.js (100%) rename {test => v2/test}/__fixtures__/custom-site/siteConfig.js (100%) rename {test => v2/test}/__fixtures__/docs/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/docs/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/docs/hello.md (100%) rename {test => v2/test}/__fixtures__/docs/permalink.md (100%) rename {test => v2/test}/__fixtures__/simple-site/pages/hello/world.js (100%) rename {test => v2/test}/__fixtures__/simple-site/pages/index.js (100%) rename {test => v2/test}/__fixtures__/simple-site/sidebars.json (100%) rename {test => v2/test}/__fixtures__/simple-site/siteConfig.js (100%) rename {test => v2/test}/__fixtures__/simple-site/static/css/basic.css (100%) rename {test => v2/test}/__fixtures__/simple-site/static/img/sakura.png (100%) rename {test => v2/test}/__fixtures__/simple-site/static/img/slash-introducing.png (100%) rename {test => v2/test}/__fixtures__/translated-site/languages.js (100%) rename {test => v2/test}/__fixtures__/translated-site/pages/hello/world.js (100%) rename {test => v2/test}/__fixtures__/translated-site/pages/index.js (100%) rename {test => v2/test}/__fixtures__/translated-site/sidebars.json (100%) rename {test => v2/test}/__fixtures__/translated-site/siteConfig.js (100%) rename {test => v2/test}/__fixtures__/translated-site/static/css/basic.css (100%) rename {test => v2/test}/__fixtures__/translated-site/static/img/sakura.png (100%) rename {test => v2/test}/__fixtures__/translated-site/static/img/slash-introducing.png (100%) rename {test => v2/test}/__fixtures__/translated-site/translated_docs/ko/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/translated-site/translated_docs/ko/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/translated-site/translated_docs/ko/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/languages.js (100%) rename {test => v2/test}/__fixtures__/transversioned-site/pages/hello/world.js (100%) rename {test => v2/test}/__fixtures__/transversioned-site/pages/index.js (100%) rename {test => v2/test}/__fixtures__/transversioned-site/sidebars.json (100%) rename {test => v2/test}/__fixtures__/transversioned-site/siteConfig.js (100%) rename {test => v2/test}/__fixtures__/transversioned-site/static/css/basic.css (100%) rename {test => v2/test}/__fixtures__/transversioned-site/static/img/sakura.png (100%) rename {test => v2/test}/__fixtures__/transversioned-site/static/img/slash-introducing.png (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json (100%) rename {test => v2/test}/__fixtures__/transversioned-site/versions.json (100%) rename {test => v2/test}/__fixtures__/versioned-site/pages/hello/world.js (100%) rename {test => v2/test}/__fixtures__/versioned-site/pages/index.js (100%) rename {test => v2/test}/__fixtures__/versioned-site/sidebars.json (100%) rename {test => v2/test}/__fixtures__/versioned-site/siteConfig.js (100%) rename {test => v2/test}/__fixtures__/versioned-site/static/css/basic.css (100%) rename {test => v2/test}/__fixtures__/versioned-site/static/img/sakura.png (100%) rename {test => v2/test}/__fixtures__/versioned-site/static/img/slash-introducing.png (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json (100%) rename {test => v2/test}/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json (100%) rename {test => v2/test}/__fixtures__/versioned-site/versions.json (100%) rename {test => v2/test}/jest.config.js (100%) rename {test => v2/test}/load/__fixtures__/bad-site/languages.js (100%) rename {test => v2/test}/load/__fixtures__/bad-site/siteConfig.js (100%) rename {test => v2/test}/load/__fixtures__/simple-pages/bar/baz.js (100%) rename {test => v2/test}/load/__fixtures__/simple-pages/foo.js (100%) rename {test => v2/test}/load/__fixtures__/simple-pages/foo/index.js (100%) rename {test => v2/test}/load/__fixtures__/simple-pages/index.js (100%) rename {test => v2/test}/load/__fixtures__/simple-site/sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/simple-site/siteConfig.js (100%) rename {test => v2/test}/load/__fixtures__/translated-site/languages.js (100%) rename {test => v2/test}/load/__fixtures__/translated-site/siteConfig.js (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/languages.js (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/siteConfig.js (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/transversioned-site/versions.json (100%) rename {test => v2/test}/load/__fixtures__/versioned-site/sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/versioned-site/siteConfig.js (100%) rename {test => v2/test}/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json (100%) rename {test => v2/test}/load/__fixtures__/versioned-site/versions.json (100%) rename {test => v2/test}/load/__fixtures__/wrong-site/siteConfig.js (100%) rename {test => v2/test}/load/__snapshots__/env.test.js.snap (100%) rename {test => v2/test}/load/config.test.js (100%) rename {test => v2/test}/load/docs/__snapshots__/index.test.js.snap (100%) rename {test => v2/test}/load/docs/__snapshots__/sidebars.test.js.snap (100%) rename {test => v2/test}/load/docs/index.test.js (100%) rename {test => v2/test}/load/docs/metadata.test.js (100%) rename {test => v2/test}/load/docs/order.test.js (100%) rename {test => v2/test}/load/docs/sidebars.test.js (100%) rename {test => v2/test}/load/env.test.js (100%) rename {test => v2/test}/load/pages.test.js (100%) rename {test => v2/test}/load/routes.test.js (100%) rename {test => v2/test}/load/utils.test.js (100%) rename {test => v2/test}/loadSetup.js (100%) rename {test => v2/test}/webpack/base.test.js (100%) rename {test => v2/test}/webpack/client.test.js (100%) rename {test => v2/test}/webpack/server.test.js (100%) rename {test => v2/test}/webpack/utils.test.js (100%) rename {website => v2/website}/blog/2018-08-08-sakura.md (100%) rename {website => v2/website}/components/Tictactoe/board.js (100%) rename {website => v2/website}/components/Tictactoe/index.js (100%) rename {website => v2/website}/components/Tictactoe/square.js (100%) rename {website => v2/website}/components/Tictactoe/styles.css (100%) rename {website => v2/website}/components/Todo/TodoItem.js (100%) rename {website => v2/website}/components/Todo/TodoList.js (100%) rename {website => v2/website}/components/Todo/index.js (100%) rename {website => v2/website}/package.json (100%) rename {website => v2/website}/pages/index.js (100%) rename {website => v2/website}/pages/tictactoe.js (100%) rename {website => v2/website}/pages/youtube.js (100%) rename {website => v2/website}/sidebars.json (100%) rename {website => v2/website}/siteConfig.js (100%) rename {website => v2/website}/static/css/basic.css (100%) rename {website => v2/website}/static/img/sakura.png (100%) rename {website => v2/website}/static/img/slash-introducing.png (100%) rename yarn.lock => v2/yarn.lock (100%) diff --git a/LICENSE.md b/v2/LICENSE.md similarity index 100% rename from LICENSE.md rename to v2/LICENSE.md diff --git a/README.md b/v2/README.md similarity index 100% rename from README.md rename to v2/README.md diff --git a/bin/munseo.js b/v2/bin/munseo.js similarity index 100% rename from bin/munseo.js rename to v2/bin/munseo.js diff --git a/docs/docusaurus.md b/v2/docs/docusaurus.md similarity index 100% rename from docs/docusaurus.md rename to v2/docs/docusaurus.md diff --git a/docs/foo/bar.md b/v2/docs/foo/bar.md similarity index 100% rename from docs/foo/bar.md rename to v2/docs/foo/bar.md diff --git a/docs/foo/baz.md b/v2/docs/foo/baz.md similarity index 100% rename from docs/foo/baz.md rename to v2/docs/foo/baz.md diff --git a/docs/hello.md b/v2/docs/hello.md similarity index 100% rename from docs/hello.md rename to v2/docs/hello.md diff --git a/docs/highlight.md b/v2/docs/highlight.md similarity index 100% rename from docs/highlight.md rename to v2/docs/highlight.md diff --git a/lib/commands/build.js b/v2/lib/commands/build.js similarity index 100% rename from lib/commands/build.js rename to v2/lib/commands/build.js diff --git a/lib/commands/eject.js b/v2/lib/commands/eject.js similarity index 100% rename from lib/commands/eject.js rename to v2/lib/commands/eject.js diff --git a/lib/commands/init.js b/v2/lib/commands/init.js similarity index 100% rename from lib/commands/init.js rename to v2/lib/commands/init.js diff --git a/lib/commands/start.js b/v2/lib/commands/start.js similarity index 100% rename from lib/commands/start.js rename to v2/lib/commands/start.js diff --git a/lib/core/App.js b/v2/lib/core/App.js similarity index 100% rename from lib/core/App.js rename to v2/lib/core/App.js diff --git a/lib/core/clientEntry.js b/v2/lib/core/clientEntry.js similarity index 100% rename from lib/core/clientEntry.js rename to v2/lib/core/clientEntry.js diff --git a/lib/core/devTemplate.ejs b/v2/lib/core/devTemplate.ejs similarity index 100% rename from lib/core/devTemplate.ejs rename to v2/lib/core/devTemplate.ejs diff --git a/lib/core/prerender.js b/v2/lib/core/prerender.js similarity index 100% rename from lib/core/prerender.js rename to v2/lib/core/prerender.js diff --git a/lib/core/serverEntry.js b/v2/lib/core/serverEntry.js similarity index 100% rename from lib/core/serverEntry.js rename to v2/lib/core/serverEntry.js diff --git a/lib/index.js b/v2/lib/index.js similarity index 100% rename from lib/index.js rename to v2/lib/index.js diff --git a/lib/load/config.js b/v2/lib/load/config.js similarity index 100% rename from lib/load/config.js rename to v2/lib/load/config.js diff --git a/lib/load/docs/index.js b/v2/lib/load/docs/index.js similarity index 100% rename from lib/load/docs/index.js rename to v2/lib/load/docs/index.js diff --git a/lib/load/docs/metadata.js b/v2/lib/load/docs/metadata.js similarity index 100% rename from lib/load/docs/metadata.js rename to v2/lib/load/docs/metadata.js diff --git a/lib/load/docs/order.js b/v2/lib/load/docs/order.js similarity index 100% rename from lib/load/docs/order.js rename to v2/lib/load/docs/order.js diff --git a/lib/load/docs/sidebars.js b/v2/lib/load/docs/sidebars.js similarity index 100% rename from lib/load/docs/sidebars.js rename to v2/lib/load/docs/sidebars.js diff --git a/lib/load/env.js b/v2/lib/load/env.js similarity index 100% rename from lib/load/env.js rename to v2/lib/load/env.js diff --git a/lib/load/index.js b/v2/lib/load/index.js similarity index 100% rename from lib/load/index.js rename to v2/lib/load/index.js diff --git a/lib/load/pages.js b/v2/lib/load/pages.js similarity index 100% rename from lib/load/pages.js rename to v2/lib/load/pages.js diff --git a/lib/load/routes.js b/v2/lib/load/routes.js similarity index 100% rename from lib/load/routes.js rename to v2/lib/load/routes.js diff --git a/lib/load/theme.js b/v2/lib/load/theme.js similarity index 100% rename from lib/load/theme.js rename to v2/lib/load/theme.js diff --git a/lib/load/utils.js b/v2/lib/load/utils.js similarity index 100% rename from lib/load/utils.js rename to v2/lib/load/utils.js diff --git a/lib/theme/Docs/index.js b/v2/lib/theme/Docs/index.js similarity index 100% rename from lib/theme/Docs/index.js rename to v2/lib/theme/Docs/index.js diff --git a/lib/theme/Docs/styles.css b/v2/lib/theme/Docs/styles.css similarity index 100% rename from lib/theme/Docs/styles.css rename to v2/lib/theme/Docs/styles.css diff --git a/lib/theme/Layout/index.js b/v2/lib/theme/Layout/index.js similarity index 100% rename from lib/theme/Layout/index.js rename to v2/lib/theme/Layout/index.js diff --git a/lib/theme/Layout/styles.css b/v2/lib/theme/Layout/styles.css similarity index 100% rename from lib/theme/Layout/styles.css rename to v2/lib/theme/Layout/styles.css diff --git a/lib/theme/Loading.js b/v2/lib/theme/Loading.js similarity index 100% rename from lib/theme/Loading.js rename to v2/lib/theme/Loading.js diff --git a/lib/theme/Markdown/anchors.js b/v2/lib/theme/Markdown/anchors.js similarity index 100% rename from lib/theme/Markdown/anchors.js rename to v2/lib/theme/Markdown/anchors.js diff --git a/lib/theme/Markdown/highlight.js b/v2/lib/theme/Markdown/highlight.js similarity index 100% rename from lib/theme/Markdown/highlight.js rename to v2/lib/theme/Markdown/highlight.js diff --git a/lib/theme/Markdown/index.js b/v2/lib/theme/Markdown/index.js similarity index 100% rename from lib/theme/Markdown/index.js rename to v2/lib/theme/Markdown/index.js diff --git a/lib/theme/Markdown/toSlug.js b/v2/lib/theme/Markdown/toSlug.js similarity index 100% rename from lib/theme/Markdown/toSlug.js rename to v2/lib/theme/Markdown/toSlug.js diff --git a/lib/theme/NotFound.js b/v2/lib/theme/NotFound.js similarity index 100% rename from lib/theme/NotFound.js rename to v2/lib/theme/NotFound.js diff --git a/lib/webpack/base.js b/v2/lib/webpack/base.js similarity index 100% rename from lib/webpack/base.js rename to v2/lib/webpack/base.js diff --git a/lib/webpack/client.js b/v2/lib/webpack/client.js similarity index 100% rename from lib/webpack/client.js rename to v2/lib/webpack/client.js diff --git a/lib/webpack/loader/markdown.js b/v2/lib/webpack/loader/markdown.js similarity index 100% rename from lib/webpack/loader/markdown.js rename to v2/lib/webpack/loader/markdown.js diff --git a/lib/webpack/server.js b/v2/lib/webpack/server.js similarity index 100% rename from lib/webpack/server.js rename to v2/lib/webpack/server.js diff --git a/lib/webpack/utils.js b/v2/lib/webpack/utils.js similarity index 100% rename from lib/webpack/utils.js rename to v2/lib/webpack/utils.js diff --git a/package.json b/v2/package.json similarity index 100% rename from package.json rename to v2/package.json diff --git a/test/__fixtures__/custom-site/pages/bar/baz.js b/v2/test/__fixtures__/custom-site/pages/bar/baz.js similarity index 100% rename from test/__fixtures__/custom-site/pages/bar/baz.js rename to v2/test/__fixtures__/custom-site/pages/bar/baz.js diff --git a/test/__fixtures__/custom-site/pages/foo.js b/v2/test/__fixtures__/custom-site/pages/foo.js similarity index 100% rename from test/__fixtures__/custom-site/pages/foo.js rename to v2/test/__fixtures__/custom-site/pages/foo.js diff --git a/test/__fixtures__/custom-site/pages/foo/index.js b/v2/test/__fixtures__/custom-site/pages/foo/index.js similarity index 100% rename from test/__fixtures__/custom-site/pages/foo/index.js rename to v2/test/__fixtures__/custom-site/pages/foo/index.js diff --git a/test/__fixtures__/custom-site/pages/index.js b/v2/test/__fixtures__/custom-site/pages/index.js similarity index 100% rename from test/__fixtures__/custom-site/pages/index.js rename to v2/test/__fixtures__/custom-site/pages/index.js diff --git a/test/__fixtures__/custom-site/siteConfig.js b/v2/test/__fixtures__/custom-site/siteConfig.js similarity index 100% rename from test/__fixtures__/custom-site/siteConfig.js rename to v2/test/__fixtures__/custom-site/siteConfig.js diff --git a/test/__fixtures__/docs/foo/bar.md b/v2/test/__fixtures__/docs/foo/bar.md similarity index 100% rename from test/__fixtures__/docs/foo/bar.md rename to v2/test/__fixtures__/docs/foo/bar.md diff --git a/test/__fixtures__/docs/foo/baz.md b/v2/test/__fixtures__/docs/foo/baz.md similarity index 100% rename from test/__fixtures__/docs/foo/baz.md rename to v2/test/__fixtures__/docs/foo/baz.md diff --git a/test/__fixtures__/docs/hello.md b/v2/test/__fixtures__/docs/hello.md similarity index 100% rename from test/__fixtures__/docs/hello.md rename to v2/test/__fixtures__/docs/hello.md diff --git a/test/__fixtures__/docs/permalink.md b/v2/test/__fixtures__/docs/permalink.md similarity index 100% rename from test/__fixtures__/docs/permalink.md rename to v2/test/__fixtures__/docs/permalink.md diff --git a/test/__fixtures__/simple-site/pages/hello/world.js b/v2/test/__fixtures__/simple-site/pages/hello/world.js similarity index 100% rename from test/__fixtures__/simple-site/pages/hello/world.js rename to v2/test/__fixtures__/simple-site/pages/hello/world.js diff --git a/test/__fixtures__/simple-site/pages/index.js b/v2/test/__fixtures__/simple-site/pages/index.js similarity index 100% rename from test/__fixtures__/simple-site/pages/index.js rename to v2/test/__fixtures__/simple-site/pages/index.js diff --git a/test/__fixtures__/simple-site/sidebars.json b/v2/test/__fixtures__/simple-site/sidebars.json similarity index 100% rename from test/__fixtures__/simple-site/sidebars.json rename to v2/test/__fixtures__/simple-site/sidebars.json diff --git a/test/__fixtures__/simple-site/siteConfig.js b/v2/test/__fixtures__/simple-site/siteConfig.js similarity index 100% rename from test/__fixtures__/simple-site/siteConfig.js rename to v2/test/__fixtures__/simple-site/siteConfig.js diff --git a/test/__fixtures__/simple-site/static/css/basic.css b/v2/test/__fixtures__/simple-site/static/css/basic.css similarity index 100% rename from test/__fixtures__/simple-site/static/css/basic.css rename to v2/test/__fixtures__/simple-site/static/css/basic.css diff --git a/test/__fixtures__/simple-site/static/img/sakura.png b/v2/test/__fixtures__/simple-site/static/img/sakura.png similarity index 100% rename from test/__fixtures__/simple-site/static/img/sakura.png rename to v2/test/__fixtures__/simple-site/static/img/sakura.png diff --git a/test/__fixtures__/simple-site/static/img/slash-introducing.png b/v2/test/__fixtures__/simple-site/static/img/slash-introducing.png similarity index 100% rename from test/__fixtures__/simple-site/static/img/slash-introducing.png rename to v2/test/__fixtures__/simple-site/static/img/slash-introducing.png diff --git a/test/__fixtures__/translated-site/languages.js b/v2/test/__fixtures__/translated-site/languages.js similarity index 100% rename from test/__fixtures__/translated-site/languages.js rename to v2/test/__fixtures__/translated-site/languages.js diff --git a/test/__fixtures__/translated-site/pages/hello/world.js b/v2/test/__fixtures__/translated-site/pages/hello/world.js similarity index 100% rename from test/__fixtures__/translated-site/pages/hello/world.js rename to v2/test/__fixtures__/translated-site/pages/hello/world.js diff --git a/test/__fixtures__/translated-site/pages/index.js b/v2/test/__fixtures__/translated-site/pages/index.js similarity index 100% rename from test/__fixtures__/translated-site/pages/index.js rename to v2/test/__fixtures__/translated-site/pages/index.js diff --git a/test/__fixtures__/translated-site/sidebars.json b/v2/test/__fixtures__/translated-site/sidebars.json similarity index 100% rename from test/__fixtures__/translated-site/sidebars.json rename to v2/test/__fixtures__/translated-site/sidebars.json diff --git a/test/__fixtures__/translated-site/siteConfig.js b/v2/test/__fixtures__/translated-site/siteConfig.js similarity index 100% rename from test/__fixtures__/translated-site/siteConfig.js rename to v2/test/__fixtures__/translated-site/siteConfig.js diff --git a/test/__fixtures__/translated-site/static/css/basic.css b/v2/test/__fixtures__/translated-site/static/css/basic.css similarity index 100% rename from test/__fixtures__/translated-site/static/css/basic.css rename to v2/test/__fixtures__/translated-site/static/css/basic.css diff --git a/test/__fixtures__/translated-site/static/img/sakura.png b/v2/test/__fixtures__/translated-site/static/img/sakura.png similarity index 100% rename from test/__fixtures__/translated-site/static/img/sakura.png rename to v2/test/__fixtures__/translated-site/static/img/sakura.png diff --git a/test/__fixtures__/translated-site/static/img/slash-introducing.png b/v2/test/__fixtures__/translated-site/static/img/slash-introducing.png similarity index 100% rename from test/__fixtures__/translated-site/static/img/slash-introducing.png rename to v2/test/__fixtures__/translated-site/static/img/slash-introducing.png diff --git a/test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md b/v2/test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md rename to v2/test/__fixtures__/translated-site/translated_docs/ko/foo/bar.md diff --git a/test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md b/v2/test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md rename to v2/test/__fixtures__/translated-site/translated_docs/ko/foo/baz.md diff --git a/test/__fixtures__/translated-site/translated_docs/ko/hello.md b/v2/test/__fixtures__/translated-site/translated_docs/ko/hello.md similarity index 100% rename from test/__fixtures__/translated-site/translated_docs/ko/hello.md rename to v2/test/__fixtures__/translated-site/translated_docs/ko/hello.md diff --git a/test/__fixtures__/transversioned-site/languages.js b/v2/test/__fixtures__/transversioned-site/languages.js similarity index 100% rename from test/__fixtures__/transversioned-site/languages.js rename to v2/test/__fixtures__/transversioned-site/languages.js diff --git a/test/__fixtures__/transversioned-site/pages/hello/world.js b/v2/test/__fixtures__/transversioned-site/pages/hello/world.js similarity index 100% rename from test/__fixtures__/transversioned-site/pages/hello/world.js rename to v2/test/__fixtures__/transversioned-site/pages/hello/world.js diff --git a/test/__fixtures__/transversioned-site/pages/index.js b/v2/test/__fixtures__/transversioned-site/pages/index.js similarity index 100% rename from test/__fixtures__/transversioned-site/pages/index.js rename to v2/test/__fixtures__/transversioned-site/pages/index.js diff --git a/test/__fixtures__/transversioned-site/sidebars.json b/v2/test/__fixtures__/transversioned-site/sidebars.json similarity index 100% rename from test/__fixtures__/transversioned-site/sidebars.json rename to v2/test/__fixtures__/transversioned-site/sidebars.json diff --git a/test/__fixtures__/transversioned-site/siteConfig.js b/v2/test/__fixtures__/transversioned-site/siteConfig.js similarity index 100% rename from test/__fixtures__/transversioned-site/siteConfig.js rename to v2/test/__fixtures__/transversioned-site/siteConfig.js diff --git a/test/__fixtures__/transversioned-site/static/css/basic.css b/v2/test/__fixtures__/transversioned-site/static/css/basic.css similarity index 100% rename from test/__fixtures__/transversioned-site/static/css/basic.css rename to v2/test/__fixtures__/transversioned-site/static/css/basic.css diff --git a/test/__fixtures__/transversioned-site/static/img/sakura.png b/v2/test/__fixtures__/transversioned-site/static/img/sakura.png similarity index 100% rename from test/__fixtures__/transversioned-site/static/img/sakura.png rename to v2/test/__fixtures__/transversioned-site/static/img/sakura.png diff --git a/test/__fixtures__/transversioned-site/static/img/slash-introducing.png b/v2/test/__fixtures__/transversioned-site/static/img/slash-introducing.png similarity index 100% rename from test/__fixtures__/transversioned-site/static/img/slash-introducing.png rename to v2/test/__fixtures__/transversioned-site/static/img/slash-introducing.png diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/foo/bar.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/foo/baz.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/hello.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/hello.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/bar.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/foo/baz.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.0/hello.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/bar.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/foo/baz.md diff --git a/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md b/v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md similarity index 100% rename from test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md rename to v2/test/__fixtures__/transversioned-site/translated_docs/ko/version-1.0.1/hello.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/bar.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/foo/baz.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.0/hello.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/bar.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/foo/baz.md diff --git a/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md b/v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md rename to v2/test/__fixtures__/transversioned-site/versioned_docs/version-1.0.1/hello.md diff --git a/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/v2/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json rename to v2/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json diff --git a/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/v2/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json similarity index 100% rename from test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json rename to v2/test/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json diff --git a/test/__fixtures__/transversioned-site/versions.json b/v2/test/__fixtures__/transversioned-site/versions.json similarity index 100% rename from test/__fixtures__/transversioned-site/versions.json rename to v2/test/__fixtures__/transversioned-site/versions.json diff --git a/test/__fixtures__/versioned-site/pages/hello/world.js b/v2/test/__fixtures__/versioned-site/pages/hello/world.js similarity index 100% rename from test/__fixtures__/versioned-site/pages/hello/world.js rename to v2/test/__fixtures__/versioned-site/pages/hello/world.js diff --git a/test/__fixtures__/versioned-site/pages/index.js b/v2/test/__fixtures__/versioned-site/pages/index.js similarity index 100% rename from test/__fixtures__/versioned-site/pages/index.js rename to v2/test/__fixtures__/versioned-site/pages/index.js diff --git a/test/__fixtures__/versioned-site/sidebars.json b/v2/test/__fixtures__/versioned-site/sidebars.json similarity index 100% rename from test/__fixtures__/versioned-site/sidebars.json rename to v2/test/__fixtures__/versioned-site/sidebars.json diff --git a/test/__fixtures__/versioned-site/siteConfig.js b/v2/test/__fixtures__/versioned-site/siteConfig.js similarity index 100% rename from test/__fixtures__/versioned-site/siteConfig.js rename to v2/test/__fixtures__/versioned-site/siteConfig.js diff --git a/test/__fixtures__/versioned-site/static/css/basic.css b/v2/test/__fixtures__/versioned-site/static/css/basic.css similarity index 100% rename from test/__fixtures__/versioned-site/static/css/basic.css rename to v2/test/__fixtures__/versioned-site/static/css/basic.css diff --git a/test/__fixtures__/versioned-site/static/img/sakura.png b/v2/test/__fixtures__/versioned-site/static/img/sakura.png similarity index 100% rename from test/__fixtures__/versioned-site/static/img/sakura.png rename to v2/test/__fixtures__/versioned-site/static/img/sakura.png diff --git a/test/__fixtures__/versioned-site/static/img/slash-introducing.png b/v2/test/__fixtures__/versioned-site/static/img/slash-introducing.png similarity index 100% rename from test/__fixtures__/versioned-site/static/img/slash-introducing.png rename to v2/test/__fixtures__/versioned-site/static/img/slash-introducing.png diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/baz.md diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/bar.md diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/foo/baz.md diff --git a/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md b/v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md similarity index 100% rename from test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md rename to v2/test/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md diff --git a/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/v2/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json similarity index 100% rename from test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json rename to v2/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json diff --git a/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/v2/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json similarity index 100% rename from test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json rename to v2/test/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json diff --git a/test/__fixtures__/versioned-site/versions.json b/v2/test/__fixtures__/versioned-site/versions.json similarity index 100% rename from test/__fixtures__/versioned-site/versions.json rename to v2/test/__fixtures__/versioned-site/versions.json diff --git a/test/jest.config.js b/v2/test/jest.config.js similarity index 100% rename from test/jest.config.js rename to v2/test/jest.config.js diff --git a/test/load/__fixtures__/bad-site/languages.js b/v2/test/load/__fixtures__/bad-site/languages.js similarity index 100% rename from test/load/__fixtures__/bad-site/languages.js rename to v2/test/load/__fixtures__/bad-site/languages.js diff --git a/test/load/__fixtures__/bad-site/siteConfig.js b/v2/test/load/__fixtures__/bad-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/bad-site/siteConfig.js rename to v2/test/load/__fixtures__/bad-site/siteConfig.js diff --git a/test/load/__fixtures__/simple-pages/bar/baz.js b/v2/test/load/__fixtures__/simple-pages/bar/baz.js similarity index 100% rename from test/load/__fixtures__/simple-pages/bar/baz.js rename to v2/test/load/__fixtures__/simple-pages/bar/baz.js diff --git a/test/load/__fixtures__/simple-pages/foo.js b/v2/test/load/__fixtures__/simple-pages/foo.js similarity index 100% rename from test/load/__fixtures__/simple-pages/foo.js rename to v2/test/load/__fixtures__/simple-pages/foo.js diff --git a/test/load/__fixtures__/simple-pages/foo/index.js b/v2/test/load/__fixtures__/simple-pages/foo/index.js similarity index 100% rename from test/load/__fixtures__/simple-pages/foo/index.js rename to v2/test/load/__fixtures__/simple-pages/foo/index.js diff --git a/test/load/__fixtures__/simple-pages/index.js b/v2/test/load/__fixtures__/simple-pages/index.js similarity index 100% rename from test/load/__fixtures__/simple-pages/index.js rename to v2/test/load/__fixtures__/simple-pages/index.js diff --git a/test/load/__fixtures__/simple-site/sidebars.json b/v2/test/load/__fixtures__/simple-site/sidebars.json similarity index 100% rename from test/load/__fixtures__/simple-site/sidebars.json rename to v2/test/load/__fixtures__/simple-site/sidebars.json diff --git a/test/load/__fixtures__/simple-site/siteConfig.js b/v2/test/load/__fixtures__/simple-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/simple-site/siteConfig.js rename to v2/test/load/__fixtures__/simple-site/siteConfig.js diff --git a/test/load/__fixtures__/translated-site/languages.js b/v2/test/load/__fixtures__/translated-site/languages.js similarity index 100% rename from test/load/__fixtures__/translated-site/languages.js rename to v2/test/load/__fixtures__/translated-site/languages.js diff --git a/test/load/__fixtures__/translated-site/siteConfig.js b/v2/test/load/__fixtures__/translated-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/translated-site/siteConfig.js rename to v2/test/load/__fixtures__/translated-site/siteConfig.js diff --git a/test/load/__fixtures__/transversioned-site/languages.js b/v2/test/load/__fixtures__/transversioned-site/languages.js similarity index 100% rename from test/load/__fixtures__/transversioned-site/languages.js rename to v2/test/load/__fixtures__/transversioned-site/languages.js diff --git a/test/load/__fixtures__/transversioned-site/sidebars.json b/v2/test/load/__fixtures__/transversioned-site/sidebars.json similarity index 100% rename from test/load/__fixtures__/transversioned-site/sidebars.json rename to v2/test/load/__fixtures__/transversioned-site/sidebars.json diff --git a/test/load/__fixtures__/transversioned-site/siteConfig.js b/v2/test/load/__fixtures__/transversioned-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/transversioned-site/siteConfig.js rename to v2/test/load/__fixtures__/transversioned-site/siteConfig.js diff --git a/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/v2/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json similarity index 100% rename from test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json rename to v2/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.0-sidebars.json diff --git a/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/v2/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json similarity index 100% rename from test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json rename to v2/test/load/__fixtures__/transversioned-site/versioned_sidebars/version-1.0.1-sidebars.json diff --git a/test/load/__fixtures__/transversioned-site/versions.json b/v2/test/load/__fixtures__/transversioned-site/versions.json similarity index 100% rename from test/load/__fixtures__/transversioned-site/versions.json rename to v2/test/load/__fixtures__/transversioned-site/versions.json diff --git a/test/load/__fixtures__/versioned-site/sidebars.json b/v2/test/load/__fixtures__/versioned-site/sidebars.json similarity index 100% rename from test/load/__fixtures__/versioned-site/sidebars.json rename to v2/test/load/__fixtures__/versioned-site/sidebars.json diff --git a/test/load/__fixtures__/versioned-site/siteConfig.js b/v2/test/load/__fixtures__/versioned-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/versioned-site/siteConfig.js rename to v2/test/load/__fixtures__/versioned-site/siteConfig.js diff --git a/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json b/v2/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json similarity index 100% rename from test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json rename to v2/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.0-sidebars.json diff --git a/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json b/v2/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json similarity index 100% rename from test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json rename to v2/test/load/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json diff --git a/test/load/__fixtures__/versioned-site/versions.json b/v2/test/load/__fixtures__/versioned-site/versions.json similarity index 100% rename from test/load/__fixtures__/versioned-site/versions.json rename to v2/test/load/__fixtures__/versioned-site/versions.json diff --git a/test/load/__fixtures__/wrong-site/siteConfig.js b/v2/test/load/__fixtures__/wrong-site/siteConfig.js similarity index 100% rename from test/load/__fixtures__/wrong-site/siteConfig.js rename to v2/test/load/__fixtures__/wrong-site/siteConfig.js diff --git a/test/load/__snapshots__/env.test.js.snap b/v2/test/load/__snapshots__/env.test.js.snap similarity index 100% rename from test/load/__snapshots__/env.test.js.snap rename to v2/test/load/__snapshots__/env.test.js.snap diff --git a/test/load/config.test.js b/v2/test/load/config.test.js similarity index 100% rename from test/load/config.test.js rename to v2/test/load/config.test.js diff --git a/test/load/docs/__snapshots__/index.test.js.snap b/v2/test/load/docs/__snapshots__/index.test.js.snap similarity index 100% rename from test/load/docs/__snapshots__/index.test.js.snap rename to v2/test/load/docs/__snapshots__/index.test.js.snap diff --git a/test/load/docs/__snapshots__/sidebars.test.js.snap b/v2/test/load/docs/__snapshots__/sidebars.test.js.snap similarity index 100% rename from test/load/docs/__snapshots__/sidebars.test.js.snap rename to v2/test/load/docs/__snapshots__/sidebars.test.js.snap diff --git a/test/load/docs/index.test.js b/v2/test/load/docs/index.test.js similarity index 100% rename from test/load/docs/index.test.js rename to v2/test/load/docs/index.test.js diff --git a/test/load/docs/metadata.test.js b/v2/test/load/docs/metadata.test.js similarity index 100% rename from test/load/docs/metadata.test.js rename to v2/test/load/docs/metadata.test.js diff --git a/test/load/docs/order.test.js b/v2/test/load/docs/order.test.js similarity index 100% rename from test/load/docs/order.test.js rename to v2/test/load/docs/order.test.js diff --git a/test/load/docs/sidebars.test.js b/v2/test/load/docs/sidebars.test.js similarity index 100% rename from test/load/docs/sidebars.test.js rename to v2/test/load/docs/sidebars.test.js diff --git a/test/load/env.test.js b/v2/test/load/env.test.js similarity index 100% rename from test/load/env.test.js rename to v2/test/load/env.test.js diff --git a/test/load/pages.test.js b/v2/test/load/pages.test.js similarity index 100% rename from test/load/pages.test.js rename to v2/test/load/pages.test.js diff --git a/test/load/routes.test.js b/v2/test/load/routes.test.js similarity index 100% rename from test/load/routes.test.js rename to v2/test/load/routes.test.js diff --git a/test/load/utils.test.js b/v2/test/load/utils.test.js similarity index 100% rename from test/load/utils.test.js rename to v2/test/load/utils.test.js diff --git a/test/loadSetup.js b/v2/test/loadSetup.js similarity index 100% rename from test/loadSetup.js rename to v2/test/loadSetup.js diff --git a/test/webpack/base.test.js b/v2/test/webpack/base.test.js similarity index 100% rename from test/webpack/base.test.js rename to v2/test/webpack/base.test.js diff --git a/test/webpack/client.test.js b/v2/test/webpack/client.test.js similarity index 100% rename from test/webpack/client.test.js rename to v2/test/webpack/client.test.js diff --git a/test/webpack/server.test.js b/v2/test/webpack/server.test.js similarity index 100% rename from test/webpack/server.test.js rename to v2/test/webpack/server.test.js diff --git a/test/webpack/utils.test.js b/v2/test/webpack/utils.test.js similarity index 100% rename from test/webpack/utils.test.js rename to v2/test/webpack/utils.test.js diff --git a/website/blog/2018-08-08-sakura.md b/v2/website/blog/2018-08-08-sakura.md similarity index 100% rename from website/blog/2018-08-08-sakura.md rename to v2/website/blog/2018-08-08-sakura.md diff --git a/website/components/Tictactoe/board.js b/v2/website/components/Tictactoe/board.js similarity index 100% rename from website/components/Tictactoe/board.js rename to v2/website/components/Tictactoe/board.js diff --git a/website/components/Tictactoe/index.js b/v2/website/components/Tictactoe/index.js similarity index 100% rename from website/components/Tictactoe/index.js rename to v2/website/components/Tictactoe/index.js diff --git a/website/components/Tictactoe/square.js b/v2/website/components/Tictactoe/square.js similarity index 100% rename from website/components/Tictactoe/square.js rename to v2/website/components/Tictactoe/square.js diff --git a/website/components/Tictactoe/styles.css b/v2/website/components/Tictactoe/styles.css similarity index 100% rename from website/components/Tictactoe/styles.css rename to v2/website/components/Tictactoe/styles.css diff --git a/website/components/Todo/TodoItem.js b/v2/website/components/Todo/TodoItem.js similarity index 100% rename from website/components/Todo/TodoItem.js rename to v2/website/components/Todo/TodoItem.js diff --git a/website/components/Todo/TodoList.js b/v2/website/components/Todo/TodoList.js similarity index 100% rename from website/components/Todo/TodoList.js rename to v2/website/components/Todo/TodoList.js diff --git a/website/components/Todo/index.js b/v2/website/components/Todo/index.js similarity index 100% rename from website/components/Todo/index.js rename to v2/website/components/Todo/index.js diff --git a/website/package.json b/v2/website/package.json similarity index 100% rename from website/package.json rename to v2/website/package.json diff --git a/website/pages/index.js b/v2/website/pages/index.js similarity index 100% rename from website/pages/index.js rename to v2/website/pages/index.js diff --git a/website/pages/tictactoe.js b/v2/website/pages/tictactoe.js similarity index 100% rename from website/pages/tictactoe.js rename to v2/website/pages/tictactoe.js diff --git a/website/pages/youtube.js b/v2/website/pages/youtube.js similarity index 100% rename from website/pages/youtube.js rename to v2/website/pages/youtube.js diff --git a/website/sidebars.json b/v2/website/sidebars.json similarity index 100% rename from website/sidebars.json rename to v2/website/sidebars.json diff --git a/website/siteConfig.js b/v2/website/siteConfig.js similarity index 100% rename from website/siteConfig.js rename to v2/website/siteConfig.js diff --git a/website/static/css/basic.css b/v2/website/static/css/basic.css similarity index 100% rename from website/static/css/basic.css rename to v2/website/static/css/basic.css diff --git a/website/static/img/sakura.png b/v2/website/static/img/sakura.png similarity index 100% rename from website/static/img/sakura.png rename to v2/website/static/img/sakura.png diff --git a/website/static/img/slash-introducing.png b/v2/website/static/img/slash-introducing.png similarity index 100% rename from website/static/img/slash-introducing.png rename to v2/website/static/img/slash-introducing.png diff --git a/yarn.lock b/v2/yarn.lock similarity index 100% rename from yarn.lock rename to v2/yarn.lock From 48f273e68fe76a4b171c6c6dc60b520c8a2f3e6c Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 17 Sep 2018 12:06:23 +0800 Subject: [PATCH 134/135] v2: ignore v2 folder for now --- .eslintignore | 1 + .npmignore | 1 + .prettierignore | 1 + package.json | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .prettierignore diff --git a/.eslintignore b/.eslintignore index 6cd1b6d63f..78fcb7b079 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ static/**/*.js build node_modules +v2 diff --git a/.npmignore b/.npmignore index 32f5543c28..d483cabb0d 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ yarn.lock website docs docusaurus-init +v2 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..8494ac2706 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +v2 \ No newline at end of file diff --git a/package.json b/package.json index 071f76246b..fd0931bfb7 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "jest": { "testPathIgnorePatterns": [ "/node_modules/", - "__fixtures__" + "__fixtures__", + "v2" ], "testURL": "http://localhost/" }, From dcb733a63a7037a063b7d29af820b4d8e94f9af8 Mon Sep 17 00:00:00 2001 From: endiliey Date: Mon, 17 Sep 2018 12:09:14 +0800 Subject: [PATCH 135/135] v2: nits --- v2/lib/theme/Loading.js | 2 +- v2/lib/webpack/base.js | 266 ++++++++++++++++++++-------------------- 2 files changed, 134 insertions(+), 134 deletions(-) diff --git a/v2/lib/theme/Loading.js b/v2/lib/theme/Loading.js index 44443ff411..910e0032f4 100644 --- a/v2/lib/theme/Loading.js +++ b/v2/lib/theme/Loading.js @@ -2,7 +2,7 @@ import React from 'react'; export default props => { if (props.error) { - return
    Error 🔥🔥🔥
    ; + return
    Error
    ; } if (props.pastDelay) { return
    Loading...
    ; diff --git a/v2/lib/webpack/base.js b/v2/lib/webpack/base.js index df1363ca41..61e4220a7e 100644 --- a/v2/lib/webpack/base.js +++ b/v2/lib/webpack/base.js @@ -1,133 +1,133 @@ -const Config = require('webpack-chain'); -const CSSExtractPlugin = require('mini-css-extract-plugin'); -const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const path = require('path'); - -const mdLoader = require.resolve('./loader/markdown'); - -module.exports = function createBaseConfig(props, isServer) { - const { - siteConfig, - outDir, - themePath, - docsDir, - pagesDir, - siteDir, - sourceToMetadata, - versionedDir, - translatedDir, - baseUrl - } = props; - - const config = new Config(); - const isProd = process.env.NODE_ENV === 'production'; - - config - .mode(isProd ? 'production' : 'development') - .output.path(outDir) - .filename(isProd ? '[name].[chunkhash].js' : '[name].js') - .publicPath(isProd ? baseUrl : '/'); - - if (!isProd) { - config.devtool('cheap-module-eval-source-map'); - } - - config.resolve - .set('symlinks', true) - .alias.set('@theme', themePath) - .set('@site', siteDir) - .set('@versioned_docs', versionedDir) - .set('@translated_docs', translatedDir) - .set('@docs', docsDir) - .set('@pages', pagesDir) - .set('@build', outDir) - .set('@generated', path.resolve(__dirname, '../core/generated')) - .set('@core', path.resolve(__dirname, '../core')) - .end(); - - function applyBabel(rule) { - rule - .use('babel') - .loader('babel-loader') - .options({ - babelrc: false, - presets: ['env', 'react'], - plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import'] - }); - } - - const jsRule = config.module - .rule('js') - .test(/\.js$/) - .exclude.add(filepath => { - // Always transpile lib directory - if (filepath.startsWith(path.join(__dirname, '..'))) { - return false; - } - // Don't transpile node_modules - return /node_modules/.test(filepath); - }) - .end(); - - applyBabel(jsRule); - - const mdRule = config.module.rule('markdown').test(/\.md$/); - - applyBabel(mdRule); - - mdRule - .use('markdown-loader') - .loader(mdLoader) - .options({ - siteConfig, - versionedDir, - translatedDir, - docsDir, - sourceToMetadata - }); - - const cssRule = config.module.rule('css').test(/\.css$/); - if (!isServer) { - if (isProd) { - cssRule.use('extract-css-loader').loader(CSSExtractPlugin.loader); - } else { - cssRule.use('style-loader').loader('style-loader'); - } - } - - cssRule - .use('css-loader') - .loader(isServer ? 'css-loader/locals' : 'css-loader') - .options({ - modules: true, - importLoaders: 1, - localIdentName: `[local]_[hash:base64:8]`, - sourceMap: !isProd, - minimize: true - }); - - // mini-css-extract plugin - config.plugin('extract-css').use(CSSExtractPlugin, [ - { - filename: isProd ? '[name].[chunkhash].css' : '[name].css', - chunkFilename: isProd ? '[id].[chunkhash].css' : '[id].css' - } - ]); - - if (isProd) { - config.optimization.minimizer([ - new UglifyJsPlugin({ - cache: true, - uglifyOptions: { - warnings: false, - compress: false, - ecma: 6, - mangle: true - }, - sourceMap: true - }) - ]); - } - - return config; -}; +const Config = require('webpack-chain'); +const CSSExtractPlugin = require('mini-css-extract-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const path = require('path'); + +const mdLoader = require.resolve('./loader/markdown'); + +module.exports = function createBaseConfig(props, isServer) { + const { + siteConfig, + outDir, + themePath, + docsDir, + pagesDir, + siteDir, + sourceToMetadata, + versionedDir, + translatedDir, + baseUrl + } = props; + + const config = new Config(); + const isProd = process.env.NODE_ENV === 'production'; + + config + .mode(isProd ? 'production' : 'development') + .output.path(outDir) + .filename(isProd ? '[name].[chunkhash].js' : '[name].js') + .publicPath(isProd ? baseUrl : '/'); + + if (!isProd) { + config.devtool('cheap-module-eval-source-map'); + } + + config.resolve + .set('symlinks', true) + .alias.set('@theme', themePath) + .set('@site', siteDir) + .set('@versioned_docs', versionedDir) + .set('@translated_docs', translatedDir) + .set('@docs', docsDir) + .set('@pages', pagesDir) + .set('@build', outDir) + .set('@generated', path.resolve(__dirname, '../core/generated')) + .set('@core', path.resolve(__dirname, '../core')) + .end(); + + function applyBabel(rule) { + rule + .use('babel') + .loader('babel-loader') + .options({ + babelrc: false, + presets: ['env', 'react'], + plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import'] + }); + } + + const jsRule = config.module + .rule('js') + .test(/\.js$/) + .exclude.add(filepath => { + // Always transpile lib directory + if (filepath.startsWith(path.join(__dirname, '..'))) { + return false; + } + // Don't transpile node_modules + return /node_modules/.test(filepath); + }) + .end(); + + applyBabel(jsRule); + + const mdRule = config.module.rule('markdown').test(/\.md$/); + + applyBabel(mdRule); + + mdRule + .use('markdown-loader') + .loader(mdLoader) + .options({ + siteConfig, + versionedDir, + translatedDir, + docsDir, + sourceToMetadata + }); + + const cssRule = config.module.rule('css').test(/\.css$/); + if (!isServer) { + if (isProd) { + cssRule.use('extract-css-loader').loader(CSSExtractPlugin.loader); + } else { + cssRule.use('style-loader').loader('style-loader'); + } + } + + cssRule + .use('css-loader') + .loader(isServer ? 'css-loader/locals' : 'css-loader') + .options({ + modules: true, + importLoaders: 1, + localIdentName: `[local]_[hash:base64:8]`, + sourceMap: !isProd, + minimize: true + }); + + // mini-css-extract plugin + config.plugin('extract-css').use(CSSExtractPlugin, [ + { + filename: isProd ? '[name].[chunkhash].css' : '[name].css', + chunkFilename: isProd ? '[id].[chunkhash].css' : '[id].css' + } + ]); + + if (isProd) { + config.optimization.minimizer([ + new UglifyJsPlugin({ + cache: true, + uglifyOptions: { + warnings: false, + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]); + } + + return config; +};