refactor(v2): migrate core to Typescript ❄️🌀🐋 (#1494)

* refactor(v2): add typing for docusaurus/core

* wip: last working

* refactor(v2): add typing for @docusaurus/core

* prettier

* dont run in parallel otherwise some are uncompiled

* nits

* more typing

* more typing

* nits

* type commands

* nits
This commit is contained in:
Endi 2019-05-20 23:59:04 +07:00 committed by Yangshun Tay
parent 0568ad4992
commit 305e698e6e
74 changed files with 739 additions and 488 deletions

View file

@ -11,3 +11,5 @@ packages/docusaurus-1.x/lib/core/metadata.js
packages/docusaurus-1.x/lib/core/MetadataBlog.js
packages/docusaurus-1.x/lib/core/__tests__/split-tab.test.js
packages/docusaurus-utils/lib/
packages/docusaurus/lib/

2
.gitignore vendored
View file

@ -13,4 +13,6 @@ build
.cache-loader
types
packages/docusaurus-utils/lib/
packages/docusaurus/lib/

View file

@ -3,3 +3,4 @@ node_modules
build
.docusaurus
packages/docusaurus-utils/lib/
packages/docusaurus/lib/

View file

@ -1,7 +1,6 @@
{
"bracketSpacing": false,
"jsxBracketSameLine": true,
"parser": "flow",
"printWidth": 80,
"proseWrap": "never",
"singleQuote": true,

View file

@ -13,21 +13,27 @@
"build:v1": "yarn workspace docusaurus-1-website build",
"build:v2": "yarn workspace docusaurus-2-website build",
"postinstall": "yarn tsc",
"prettier": "prettier --config .prettierrc --write \"**/*.js\"",
"prettier:diff": "prettier --config .prettierrc --list-different \"**/*.js\"",
"prettier": "prettier --config .prettierrc --write \"**/*.{js,ts}\"",
"prettier:diff": "prettier --config .prettierrc --list-different \"**/*.{js,ts}\"",
"lint": "eslint --cache \"**/*.js\"",
"lerna": "lerna",
"test": "jest",
"tsc": "lerna run --parallel tsc --no-private"
"tsc": "lerna run tsc --no-private"
},
"devDependencies": {
"@babel/core": "^7.4.4",
"@babel/preset-typescript": "^7.3.3",
"@types/chalk": "^2.2.0",
"@types/escape-string-regexp": "^1.0.0",
"@types/express": "^4.16.1",
"@types/fs-extra": "7.0.0",
"@types/globby": "9.1.0",
"@types/jest": "^24.0.13",
"@types/lodash": "^4.14.129",
"@types/node": "^12.0.2",
"@types/shelljs": "^0.8.5",
"@types/webpack": "^4.4.31",
"@types/webpack-merge": "^4.1.5",
"babel-eslint": "8",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.12.1",
@ -50,7 +56,7 @@
"react": "^16.8.4",
"react-dom": "^16.8.4",
"rimraf": "^2.6.3",
"typescript": "^3.4.5"
"typescript": "^3.5.0-rc"
},
"lint-staged": {
"linters": {

View file

@ -102,7 +102,7 @@ export function genChunkName(
prefix?: string,
preferredName?: string,
): string {
let chunkName = chunkNameCache.get(modulePath);
let chunkName: string | undefined = chunkNameCache.get(modulePath);
if (!chunkName) {
let str = modulePath;
if (preferredName) {
@ -146,10 +146,10 @@ export function parse(
fileString: string,
): {
frontMatter: {
[key: string]: any,
},
content: string,
excerpt: string | undefined,
[key: string]: any;
};
content: string;
excerpt: string | undefined;
} {
const options: {} = {
excerpt: (file: matter.GrayMatterFile<string>): void => {

View file

@ -1,6 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"outDir": "lib",
}

View file

@ -0,0 +1,2 @@
src
copyUntypedFiles.js

View file

@ -12,7 +12,7 @@ const envinfo = require('envinfo');
const semver = require('semver');
const path = require('path');
const program = require('commander');
const {build, swizzle, init, deploy, start} = require('../src');
const {build, swizzle, init, deploy, start} = require('../lib');
const requiredVersion = require('../package.json').engines.node;
if (!semver.satisfies(process.version, requiredVersion)) {

View file

@ -0,0 +1,19 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const fs = require('fs-extra');
/**
* Copy all untyped and static assets files to lib.
*/
const srcDir = path.resolve(__dirname, 'src');
const libDir = path.resolve(__dirname, 'lib');
fs.copySync(srcDir, libDir, {
filter(filepath) {
return !/__tests__/.test(filepath) && !/\.ts$/.test(filepath);
},
});

View file

@ -23,7 +23,7 @@
"docusaurus": "bin/docusaurus.js"
},
"scripts": {
"docusaurus": "node bin/docusaurus"
"tsc": "tsc && node copyUntypedFiles.js"
},
"bugs": {
"url": "https://github.com/facebook/Docusaurus/issues"

View file

@ -5,21 +5,21 @@
* LICENSE file in the root directory of this source tree.
*/
const webpack = require('webpack');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ReactLoadableSSRAddon = require('react-loadable-ssr-addon');
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
const path = require('path');
const chalk = require('chalk');
const fs = require('fs-extra');
const globby = require('globby');
const load = require('../server');
const createServerConfig = require('../webpack/server');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');
import webpack, {Configuration, Plugin} from 'webpack';
import merge from 'webpack-merge';
import CleanWebpackPlugin from 'clean-webpack-plugin';
import ReactLoadableSSRAddon from 'react-loadable-ssr-addon';
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
import path from 'path';
import chalk from 'chalk';
import fs from 'fs-extra';
import globby from 'globby';
import {load, CLIOptions, Props} from '../server';
import {createClientConfig} from '../webpack/client';
import {createServerConfig} from '../webpack/server';
import {applyConfigureWebpack} from '../webpack/utils';
function compile(config) {
function compile(config: Configuration[]): Promise<any> {
return new Promise((resolve, reject) => {
const compiler = webpack(config);
compiler.run((err, stats) => {
@ -42,16 +42,19 @@ function compile(config) {
});
}
module.exports = async function build(siteDir, cliOptions = {}) {
export async function build(
siteDir: string,
cliOptions: CLIOptions = {},
): Promise<void> {
process.env.NODE_ENV = 'production';
console.log(chalk.blue('Creating an optimized production build...'));
const props = await load(siteDir, cliOptions);
const props: Props = await load(siteDir, cliOptions);
// Apply user webpack config.
const {outDir, plugins} = props;
let clientConfig = merge(createClientConfig(props), {
let clientConfig: Configuration = merge(createClientConfig(props), {
plugins: [
// Remove/clean build folders before building bundles.
new CleanWebpackPlugin({verbose: false}),
@ -61,10 +64,10 @@ module.exports = async function build(siteDir, cliOptions = {}) {
new ReactLoadableSSRAddon({
filename: 'client-manifest.json',
}),
].filter(Boolean),
].filter(Boolean) as Plugin[],
});
let serverConfig = createServerConfig(props);
let serverConfig: Configuration = createServerConfig(props);
// Plugin lifecycle - configureWebpack
plugins.forEach(plugin => {
@ -88,7 +91,9 @@ module.exports = async function build(siteDir, cliOptions = {}) {
await compile([clientConfig, serverConfig]);
// Remove server.bundle.js because it is useless
await fs.unlink(path.join(outDir, serverConfig.output.filename));
if (serverConfig.output && serverConfig.output.filename) {
await fs.unlink(path.join(outDir, serverConfig.output.filename));
}
// Copy static files.
const staticDir = path.resolve(siteDir, 'static');
@ -121,4 +126,4 @@ module.exports = async function build(siteDir, cliOptions = {}) {
relativeDir,
)}.\n`,
);
};
}

View file

@ -5,14 +5,14 @@
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const shell = require('shelljs');
const fs = require('fs-extra');
const build = require('./build');
const loadConfig = require('../server/load/config');
const {CONFIG_FILE_NAME} = require('../constants');
import path from 'path';
import shell from 'shelljs';
import fs from 'fs-extra';
import {build} from './build';
import {loadConfig} from '../server/config';
import {CONFIG_FILE_NAME} from '../constants';
module.exports = async function deploy(siteDir) {
export async function deploy(siteDir: string): Promise<void> {
console.log('Deploy command invoked ...');
if (!shell.which('git')) {
throw new Error('Sorry, this script requires git');
@ -136,57 +136,38 @@ module.exports = async function deploy(siteDir) {
'.docusaurus',
`${projectName}-${deploymentBranch}`,
);
// In github.io case, project is deployed to root. Need to not recursively
// copy the deployment-branch to be.
const excludePath = `${projectName}-${deploymentBranch}`;
// cannot use shell.cp because it doesn't support copying dotfiles and we
// need to copy directories like .circleci, for example
// https://github.com/shelljs/shelljs/issues/79
fs.copy(
fromPath,
toPath,
src => {
if (src.indexOf('.DS_Store') !== -1) {
return false;
}
if (src.indexOf(excludePath) !== -1) {
return false;
}
return true;
},
error => {
if (error) {
throw new Error(
`Error: Copying build assets failed with error '${error}'`,
);
}
fs.copy(fromPath, toPath, error => {
if (error) {
throw new Error(
`Error: Copying build assets failed with error '${error}'`,
);
}
shell.cd(toPath);
shell.exec('git add --all');
shell.cd(toPath);
shell.exec('git add --all');
const commitMessage =
process.env.CUSTOM_COMMIT_MESSAGE ||
`Deploy website version based on ${currentCommit}`;
const commitResults = shell.exec(`git commit -m "${commitMessage}"`);
if (
shell.exec(`git push --force origin ${deploymentBranch}`).code !== 0
) {
throw new Error('Error: Git push failed');
} else if (commitResults.code === 0) {
// The commit might return a non-zero value when site is up to date.
const websiteURL =
githubHost === 'github.com'
? `https://${organizationName}.github.io/${projectName}` // gh-pages hosted repo
: `https://${githubHost}/pages/${organizationName}/${projectName}`; // GitHub enterprise hosting.
shell.echo(`Website is live at: ${websiteURL}`);
shell.exit(0);
}
},
);
const commitMessage =
process.env.CUSTOM_COMMIT_MESSAGE ||
`Deploy website version based on ${currentCommit}`;
const commitResults = shell.exec(`git commit -m "${commitMessage}"`);
if (
shell.exec(`git push --force origin ${deploymentBranch}`).code !== 0
) {
throw new Error('Error: Git push failed');
} else if (commitResults.code === 0) {
// The commit might return a non-zero value when site is up to date.
const websiteURL =
githubHost === 'github.com'
? `https://${organizationName}.github.io/${projectName}` // gh-pages hosted repo
: `https://${githubHost}/pages/${organizationName}/${projectName}`; // GitHub enterprise hosting.
shell.echo(`Website is live at: ${websiteURL}`);
shell.exit(0);
}
});
})
.catch(buildError => {
console.error(buildError);
process.exit(1);
});
};
}

View file

@ -5,10 +5,15 @@
* LICENSE file in the root directory of this source tree.
*/
module.exports = async function init(projectDir, cliOptions = {}) {
import {CLIOptions} from '../server';
export async function init(
projectDir: string,
cliOptions: CLIOptions = {},
): Promise<void> {
console.log('Init command invoked ...');
console.log(projectDir);
console.log(cliOptions);
// TODO
};
}

View file

@ -5,36 +5,39 @@
* LICENSE file in the root directory of this source tree.
*/
const _ = require('lodash');
const path = require('path');
const express = require('express');
const chalk = require('chalk');
const webpack = require('webpack');
const chokidar = require('chokidar');
const portfinder = require('portfinder');
const openBrowser = require('react-dev-utils/openBrowser');
const {prepareUrls} = require('react-dev-utils/WebpackDevServerUtils');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
const WebpackDevServer = require('webpack-dev-server');
const merge = require('webpack-merge');
const {normalizeUrl} = require('@docusaurus/utils');
const load = require('../server');
const {CONFIG_FILE_NAME} = require('../constants');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');
import _ from 'lodash';
import path from 'path';
import webpack from 'webpack';
import express from 'express';
import chalk from 'chalk';
import chokidar from 'chokidar';
import portfinder from 'portfinder';
import openBrowser from 'react-dev-utils/openBrowser';
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import HotModuleReplacementPlugin from 'webpack/lib/HotModuleReplacementPlugin';
import WebpackDevServer from 'webpack-dev-server';
import merge from 'webpack-merge';
import {normalizeUrl} from '@docusaurus/utils';
import {load, CLIOptions} from '../server';
import {CONFIG_FILE_NAME} from '../constants';
import {createClientConfig} from '../webpack/client';
import {applyConfigureWebpack} from '../webpack/utils';
function getHost(reqHost) {
function getHost(reqHost: string | undefined): string {
return reqHost || 'localhost';
}
async function getPort(reqPort) {
portfinder.basePort = parseInt(reqPort, 10) || 3000;
async function getPort(reqPort: string | undefined): Promise<number> {
portfinder.basePort = reqPort ? parseInt(reqPort, 10) : 3000;
const port = await portfinder.getPortPromise();
return port;
}
module.exports = async function start(siteDir, cliOptions = {}) {
export async function start(
siteDir: string,
cliOptions: CLIOptions = {},
): Promise<void> {
console.log(chalk.blue('Starting the development server...'));
// Process all related files as a prop.
@ -126,16 +129,9 @@ module.exports = async function start(siteDir, cliOptions = {}) {
// Enable overlay on browser. E.g: display errors
overlay: true,
host,
// https://webpack.js.org/configuration/dev-server/#devserverbefore
// eslint-disable-next-line
before(app, server) {
before(app) {
app.use(baseUrl, express.static(path.resolve(siteDir, 'static')));
// TODO: add plugins beforeDevServer hook
},
// https://webpack.js.org/configuration/dev-server/#devserverbefore
// eslint-disable-next-line
after(app, server) {
// TODO: add plugins afterDevServer hook
// TODO: add plugins beforeDevServer and afterDevServer hook
},
};
WebpackDevServer.addDevServerEntrypoints(config, devServerConfig);
@ -148,9 +144,9 @@ module.exports = async function start(siteDir, cliOptions = {}) {
openBrowser(openUrl);
});
['SIGINT', 'SIGTERM'].forEach(sig => {
process.on(sig, () => {
process.on(sig as NodeJS.Signals, () => {
devServer.close();
process.exit();
});
});
};
}

View file

@ -5,12 +5,16 @@
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const chalk = require('chalk');
const path = require('path');
const importFresh = require('import-fresh');
import fs from 'fs-extra';
import chalk from 'chalk';
import path from 'path';
import importFresh from 'import-fresh';
module.exports = async function swizzle(siteDir, themeName, componentName) {
export async function swizzle(
siteDir: string,
themeName: string,
componentName?: string,
): Promise<void> {
const Plugin = importFresh(themeName);
const context = {siteDir};
const PluginInstance = new Plugin(context);
@ -33,4 +37,4 @@ module.exports = async function swizzle(siteDir, themeName, componentName) {
`\n${chalk.green('Success!')} Copied ${fromMsg} to ${toMsg}.\n`,
);
}
};
}

View file

@ -5,7 +5,5 @@
* LICENSE file in the root directory of this source tree.
*/
module.exports = {
GENERATED_FILES_DIR_NAME: '.docusaurus',
CONFIG_FILE_NAME: 'docusaurus.config.js',
};
export const GENERATED_FILES_DIR_NAME = '.docusaurus';
export const CONFIG_FILE_NAME = 'docusaurus.config.js';

View file

@ -1,20 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const build = require('./commands/build');
const init = require('./commands/init');
const start = require('./commands/start');
const swizzle = require('./commands/swizzle');
const deploy = require('./commands/deploy');
module.exports = {
build,
swizzle,
init,
start,
deploy,
};

View file

@ -0,0 +1,12 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
export {build} from './commands/build';
export {init} from './commands/init';
export {start} from './commands/start';
export {swizzle} from './commands/swizzle';
export {deploy} from './commands/deploy';

View file

@ -6,12 +6,12 @@
*/
import path from 'path';
import loadConfig from '../config';
import loadSetup from '../loadSetup';
import {loadConfig} from '../config';
describe('loadConfig', () => {
test('website with valid siteConfig', async () => {
const {siteDir} = await loadSetup('simple');
const fixtures = path.join(__dirname, '__fixtures__');
const siteDir = path.join(fixtures, 'simple-site');
const config = loadConfig(siteDir);
expect(config).toMatchInlineSnapshot(
{
@ -38,7 +38,7 @@ describe('loadConfig', () => {
expect(() => {
loadConfig(siteDir);
}).toThrowErrorMatchingInlineSnapshot(
`"The required field(s) 'favicon', 'organizationName', 'projectName', 'tagline', 'url' are missing from docusaurus.config.js"`,
`"The required field(s) 'favicon', 'tagline', 'url' are missing from docusaurus.config.js"`,
);
});
@ -55,8 +55,6 @@ describe('loadConfig', () => {
const siteDir = path.join(__dirname, '__fixtures__', 'nonExisting');
expect(() => {
loadConfig(siteDir);
}).toThrowErrorMatchingInlineSnapshot(
`"The required field(s) 'baseUrl', 'favicon', 'organizationName', 'projectName', 'tagline', 'title', 'url' are missing from docusaurus.config.js"`,
);
}).toThrowErrorMatchingInlineSnapshot(`"docusaurus.config.js not found"`);
});
});

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import loadSetup from '../loadSetup';
import {loadSetup} from '../loadSetup';
describe('loadRoutes', () => {
test('simple website', async () => {

View file

@ -5,23 +5,35 @@
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const _ = require('lodash');
const importFresh = require('import-fresh');
const path = require('path');
const {CONFIG_FILE_NAME} = require('../../constants');
import fs from 'fs-extra';
import _ from 'lodash';
import importFresh from 'import-fresh';
import path from 'path';
import {CONFIG_FILE_NAME} from '../constants';
const REQUIRED_FIELDS = [
'baseUrl',
'favicon',
'organizationName',
'projectName',
'tagline',
'title',
'url',
];
export interface DocusaurusConfig {
baseUrl: string;
favicon: string;
tagline: string;
title: string;
url: string;
organizationName?: string;
projectName?: string;
customFields?: string[];
githubHost?: string;
plugins?: any[];
presets?: any[];
themeConfig?: {
[key: string]: any;
};
[key: string]: any;
}
const REQUIRED_FIELDS = ['baseUrl', 'favicon', 'tagline', 'title', 'url'];
const OPTIONAL_FIELDS = [
'organizationName',
'projectName',
'customFields',
'githubHost',
'plugins',
@ -29,21 +41,23 @@ const OPTIONAL_FIELDS = [
'themeConfig',
];
const DEFAULT_CONFIG = {
const DEFAULT_CONFIG: {
[key: string]: any;
} = {
plugins: [],
};
function formatFields(fields) {
function formatFields(fields: string[]): string {
return fields.map(field => `'${field}'`).join(', ');
}
function loadConfig(siteDir) {
export function loadConfig(siteDir: string): DocusaurusConfig {
const configPath = path.resolve(siteDir, CONFIG_FILE_NAME);
let loadedConfig = {};
if (fs.existsSync(configPath)) {
loadedConfig = importFresh(configPath);
}
if (!fs.existsSync(configPath)) {
throw new Error(`${CONFIG_FILE_NAME} not found`);
}
const loadedConfig = importFresh(configPath);
const missingFields = REQUIRED_FIELDS.filter(
field => !_.has(loadedConfig, field),
);
@ -56,7 +70,7 @@ function loadConfig(siteDir) {
}
// Merge default config with loaded config.
const config = {...DEFAULT_CONFIG, ...loadedConfig};
const config: DocusaurusConfig = {...DEFAULT_CONFIG, ...loadedConfig};
// 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`.
@ -81,5 +95,3 @@ function loadConfig(siteDir) {
return config;
}
module.exports = loadConfig;

View file

@ -1,138 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const {generate} = require('@docusaurus/utils');
const loadConfig = require('./load/config');
const loadTheme = require('./load/theme');
const loadRoutes = require('./load/routes');
const loadPlugins = require('./load/plugins');
const loadPresets = require('./load/presets');
const constants = require('../constants');
module.exports = async function load(siteDir, cliOptions = {}) {
const generatedFilesDir = path.resolve(
siteDir,
constants.GENERATED_FILES_DIR_NAME,
);
const siteConfig = loadConfig(siteDir);
await generate(
generatedFilesDir,
constants.CONFIG_FILE_NAME,
`export default ${JSON.stringify(siteConfig, null, 2)};`,
);
const context = {siteDir, generatedFilesDir, siteConfig, cliOptions};
// Process presets.
const {plugins: presetPlugins, themes: presetThemes} = loadPresets(context);
// Process plugins and themes. Themes are also plugins, but they run after all
// the explicit plugins because they may override the resolve.alias(es)
// defined by the plugins.
const pluginConfigs = [
...presetPlugins,
...(siteConfig.plugins || []),
...presetThemes,
...(siteConfig.themes || []),
];
const {plugins, pluginsRouteConfigs} = await loadPlugins({
pluginConfigs,
context,
});
const outDir = path.resolve(siteDir, 'build');
const {baseUrl} = siteConfig;
// Default theme components that are essential and must exist in a Docusaurus app
// These can be overriden in plugins/ through component swizzling.
// However, we alias it here first as a fallback.
const themeFallback = path.resolve(__dirname, '../client/theme-fallback');
const fallbackAliases = await loadTheme(themeFallback);
// Create theme alias from plugins.
const pluginThemeAliases = await Promise.all(
plugins.map(async plugin => {
if (!plugin.getThemePath) {
return null;
}
return loadTheme(plugin.getThemePath());
}),
);
// User's own theme alias override. Highest priority.
const themePath = path.resolve(siteDir, 'theme');
const userAliases = await loadTheme(themePath);
const combinedAliases = [
fallbackAliases,
...pluginThemeAliases,
userAliases,
].reduce(
(acc, curr) => ({
...acc,
...curr,
}),
{},
);
// Make a fake plugin to resolve aliased theme components.
plugins.push({
configureWebpack: () => ({
resolve: {
alias: combinedAliases,
},
}),
});
// Routing
const {
registry,
routesChunkNames,
routesConfig,
routesPaths,
} = await loadRoutes(pluginsRouteConfigs);
await generate(
generatedFilesDir,
'registry.js',
`export default {
${Object.keys(registry)
.map(
key => ` '${key}': {
'importStatement': ${registry[key].importStatement},
'module': '${registry[key].modulePath}',
'webpack': require.resolveWeak('${registry[key].modulePath}'),
},`,
)
.join('\n')}};\n`,
);
await generate(
generatedFilesDir,
'routesChunkNames.json',
JSON.stringify(routesChunkNames, null, 2),
);
await generate(generatedFilesDir, 'routes.js', routesConfig);
const props = {
siteConfig,
siteDir,
outDir,
baseUrl,
generatedFilesDir,
routesPaths,
plugins,
cliOptions,
};
return props;
};

View file

@ -0,0 +1,137 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import {generate} from '@docusaurus/utils';
import {loadConfig, DocusaurusConfig} from './config';
import {loadThemeAlias} from './themes';
import {loadPlugins} from './plugins';
import {loadRoutes} from './routes';
import {loadPresets} from './presets';
import {GENERATED_FILES_DIR_NAME, CONFIG_FILE_NAME} from '../constants';
export interface CLIOptions {
[option: string]: any;
}
export interface LoadContext {
siteDir: string;
generatedFilesDir: string;
siteConfig: DocusaurusConfig;
cliOptions: CLIOptions;
outDir: string;
baseUrl: string;
}
export interface Props extends LoadContext {
routesPaths: string[];
plugins: any[];
}
export async function load(
siteDir: string,
cliOptions: CLIOptions = {},
): Promise<Props> {
const generatedFilesDir: string = path.resolve(
siteDir,
GENERATED_FILES_DIR_NAME,
);
const siteConfig: DocusaurusConfig = loadConfig(siteDir);
await generate(
generatedFilesDir,
CONFIG_FILE_NAME,
`export default ${JSON.stringify(siteConfig, null, 2)};`,
);
const outDir = path.resolve(siteDir, 'build');
const {baseUrl} = siteConfig;
const context: LoadContext = {
siteDir,
generatedFilesDir,
siteConfig,
cliOptions,
outDir,
baseUrl,
};
/* Preset */
const {plugins: presetPlugins, themes: presetThemes} = loadPresets(context);
/* Plugin */
const pluginConfigs = [
...presetPlugins,
...(siteConfig.plugins || []),
...presetThemes,
...(siteConfig.themes || []),
];
const {plugins, pluginsRouteConfigs} = await loadPlugins({
pluginConfigs,
context,
});
/* Theme */
const fallbackTheme = path.resolve(__dirname, '../client/theme-fallback');
const pluginThemes = plugins
.map(plugin => plugin.getThemePath && plugin.getThemePath())
.filter(Boolean) as string[];
const userTheme = path.resolve(siteDir, 'theme');
const alias = loadThemeAlias([fallbackTheme, ...pluginThemes, userTheme]);
// Make a fake plugin to resolve aliased theme components.
plugins.push({
configureWebpack: () => ({
resolve: {
alias,
},
}),
});
// Routing
const {
registry,
routesChunkNames,
routesConfig,
routesPaths,
} = await loadRoutes(pluginsRouteConfigs);
await generate(
generatedFilesDir,
'registry.js',
`export default {
${Object.keys(registry)
.map(
key => ` '${key}': {
'importStatement': ${registry[key].importStatement},
'module': '${registry[key].modulePath}',
'webpack': require.resolveWeak('${registry[key].modulePath}'),
},`,
)
.join('\n')}};\n`,
);
await generate(
generatedFilesDir,
'routesChunkNames.json',
JSON.stringify(routesChunkNames, null, 2),
);
await generate(generatedFilesDir, 'routes.js', routesConfig);
const props = {
siteConfig,
siteDir,
outDir,
baseUrl,
generatedFilesDir,
routesPaths,
plugins,
cliOptions,
};
return props;
}

View file

@ -6,22 +6,19 @@
*/
import path from 'path';
import load from '../index';
import {load, Props} from './index';
// Helper methods to setup dummy/fake projects
const loadSetup = async name => {
export const loadSetup = async (name: string): Promise<Props> => {
const fixtures = path.join(__dirname, '__tests__', '__fixtures__');
const simpleSite = path.join(fixtures, 'simple-site');
const customSite = path.join(fixtures, 'custom-site');
switch (name) {
case 'simple':
return load(simpleSite);
case 'custom':
return load(customSite);
case 'simple':
default:
return {};
return load(simpleSite);
}
};
export default loadSetup;

View file

@ -5,12 +5,19 @@
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const importFresh = require('import-fresh');
const path = require('path');
const {generate} = require('@docusaurus/utils');
import fs from 'fs-extra';
import importFresh from 'import-fresh';
import path from 'path';
import {generate} from '@docusaurus/utils';
import {LoadContext} from '..';
module.exports = async function loadPlugins({pluginConfigs = [], context}) {
export async function loadPlugins({
pluginConfigs = [],
context,
}: {
pluginConfigs: any[];
context: LoadContext;
}) {
// 1. Plugin Lifecycle - Initialization/Constructor
const plugins = pluginConfigs.map(({name, path: pluginPath, options}) => {
let Plugin;
@ -37,7 +44,7 @@ module.exports = async function loadPlugins({pluginConfigs = [], context}) {
);
// 3. Plugin lifecycle - contentLoaded
const pluginsRouteConfigs = [];
const pluginsRouteConfigs: any[] = [];
await Promise.all(
plugins.map(async (plugin, index) => {
@ -68,4 +75,4 @@ module.exports = async function loadPlugins({pluginConfigs = [], context}) {
plugins,
pluginsRouteConfigs,
};
};
}

View file

@ -7,11 +7,13 @@
import path from 'path';
import loadPresets from '../presets';
import {loadPresets} from '../index';
import {LoadContext} from '../../index';
describe('loadPresets', () => {
test('no presets', () => {
const presets = loadPresets({siteConfig: {presets: []}});
const context = {siteConfig: {}} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [],
@ -21,11 +23,12 @@ Object {
});
test('string form', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [path.join(__dirname, '__fixtures__/preset-bar.js')],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -44,14 +47,15 @@ Object {
});
test('string form composite', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [
path.join(__dirname, '__fixtures__/preset-bar.js'),
path.join(__dirname, '__fixtures__/preset-foo.js'),
],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -78,11 +82,12 @@ Object {
});
test('array form', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [[path.join(__dirname, '__fixtures__/preset-bar.js')]],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -101,7 +106,7 @@ Object {
});
test('array form with options', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [
[
@ -110,7 +115,8 @@ Object {
],
],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -131,7 +137,7 @@ Object {
});
test('array form composite', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [
[
@ -144,7 +150,8 @@ Object {
],
],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -175,7 +182,7 @@ Object {
});
test('mixed form', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [
[
@ -185,7 +192,8 @@ Object {
path.join(__dirname, '__fixtures__/preset-foo.js'),
],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [
@ -214,7 +222,7 @@ Object {
});
test('mixed form with themes', () => {
const presets = loadPresets({
const context = {
siteConfig: {
presets: [
[
@ -225,7 +233,8 @@ Object {
path.join(__dirname, '__fixtures__/preset-qux.js'),
],
},
});
} as LoadContext;
const presets = loadPresets(context);
expect(presets).toMatchInlineSnapshot(`
Object {
"plugins": Array [

View file

@ -5,13 +5,14 @@
* LICENSE file in the root directory of this source tree.
*/
const importFresh = require('import-fresh');
const _ = require('lodash');
import importFresh from 'import-fresh';
import _ from 'lodash';
import {LoadContext} from '../index';
module.exports = function loadPresets(context) {
const presets = context.siteConfig.presets || [];
const plugins = [];
const themes = [];
export function loadPresets(context: LoadContext) {
const presets: any[] = context.siteConfig.presets || [];
const plugins: any[] = [];
const themes: any[] = [];
presets.forEach(presetItem => {
let presetModule;
@ -31,4 +32,4 @@ module.exports = function loadPresets(context) {
plugins: _.compact(_.flatten(plugins)),
themes: _.compact(_.flatten(themes)),
};
};
}

View file

@ -5,17 +5,29 @@
* LICENSE file in the root directory of this source tree.
*/
const {genChunkName} = require('@docusaurus/utils');
const {stringify} = require('querystring');
const _ = require('lodash');
import {genChunkName} from '@docusaurus/utils';
import {stringify} from 'querystring';
import _ from 'lodash';
async function loadRoutes(pluginsRouteConfigs) {
export interface RouteConfig {
path: string;
component: string;
modules?: {
[key: string]: any;
};
routes?: {
[route: string]: RouteConfig;
};
exact?: boolean;
}
export async function loadRoutes(pluginsRouteConfigs: RouteConfig[]) {
const routesImports = [
`import React from 'react';`,
`import ComponentCreator from '@docusaurus/ComponentCreator';`,
];
const routesPaths = [];
const addRoutesPath = routePath => {
const routesPaths: string[] = [];
const addRoutesPath = (routePath: string) => {
routesPaths.push(routePath);
};
@ -53,7 +65,7 @@ async function loadRoutes(pluginsRouteConfigs) {
return null;
}
const importStr = _.isObject(target) ? target.path : target;
const importStr = _.isObject(target as any) ? target.path : target;
const queryStr = target.query ? `?${stringify(target.query)}` : '';
return `${importStr}${queryStr}`;
};
@ -64,7 +76,11 @@ async function loadRoutes(pluginsRouteConfigs) {
const componentPath = getModulePath(component);
const genImportChunk = (modulePath, prefix, name) => {
const genImportChunk = (
modulePath: string | null | undefined,
prefix?: string,
name?: string,
) => {
if (!modulePath) {
return null;
}
@ -81,12 +97,12 @@ async function loadRoutes(pluginsRouteConfigs) {
const componentChunk = genImportChunk(componentPath, 'component');
addRoutesChunkNames(routePath, 'component', componentChunk);
function genRouteChunkNames(value, prefix) {
function genRouteChunkNames(value, prefix?: string) {
if (Array.isArray(value)) {
return value.map(genRouteChunkNames);
return value.map((val, i) => genRouteChunkNames(val, `${i}`));
}
if (_.isObject(value) && !value.__import) {
if (_.isObject(value as any) && !value.__import) {
const newValue = {};
Object.keys(value).forEach(key => {
newValue[key] = genRouteChunkNames(value[key], key);
@ -149,5 +165,3 @@ export default [
routesPaths,
};
}
module.exports = loadRoutes;

View file

@ -0,0 +1 @@
export default () => null;

View file

@ -0,0 +1 @@
export default () => null;

View file

@ -0,0 +1 @@
export default () => null;

View file

@ -0,0 +1 @@
export default () => null;

View file

@ -0,0 +1,49 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import fs from 'fs-extra';
import {themeAlias} from '../alias';
describe('themeAlias', () => {
test('valid themePath 1 with components', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'theme-1');
const alias = themeAlias(themePath);
expect(alias).toEqual({
'@theme/Footer': path.join(themePath, 'Footer/index.js'),
'@theme/Layout': path.join(themePath, 'Layout.js'),
});
expect(alias).not.toEqual({});
});
test('valid themePath 2 with components', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'theme-2');
const alias = themeAlias(themePath);
expect(alias).toEqual({
'@theme/Navbar': path.join(themePath, 'Navbar.js'),
'@theme/Layout': path.join(themePath, 'Layout/index.js'),
});
expect(alias).not.toEqual({});
});
test('valid themePath with no components', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'empty-theme');
fs.ensureDirSync(themePath);
const alias = themeAlias(themePath);
expect(alias).toEqual({});
});
test('invalid themePath that does not exist', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, '__noExist__');
const alias = themeAlias(themePath);
expect(alias).toEqual({});
});
});

View file

@ -0,0 +1,25 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import {loadThemeAlias} from '../index';
describe('loadThemeAlias', () => {
test('next alias can override the previous alias', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const theme1Path = path.join(fixtures, 'theme-1');
const theme2Path = path.join(fixtures, 'theme-2');
const alias = loadThemeAlias([theme1Path, theme2Path]);
expect(alias).toEqual({
'@theme/Footer': path.join(theme1Path, 'Footer/index.js'),
'@theme/Navbar': path.join(theme2Path, 'Navbar.js'),
'@theme/Layout': path.join(theme2Path, 'Layout/index.js'),
});
expect(alias).not.toEqual({});
});
});

View file

@ -5,22 +5,25 @@
* LICENSE file in the root directory of this source tree.
*/
const globby = require('globby');
const fs = require('fs-extra');
const path = require('path');
const {fileToPath, posixPath, normalizeUrl} = require('@docusaurus/utils');
import globby from 'globby';
import fs from 'fs-extra';
import path from 'path';
import {fileToPath, posixPath, normalizeUrl} from '@docusaurus/utils';
module.exports = async function loadTheme(themePath) {
export interface Alias {
[alias: string]: string;
}
export function themeAlias(themePath: string): Alias {
if (!fs.pathExistsSync(themePath)) {
return null;
return {};
}
const themeComponentFiles = await globby(['**/*.{js,jsx}'], {
const themeComponentFiles = globby.sync(['**/*.{js,jsx}'], {
cwd: themePath,
});
const alias = {};
themeComponentFiles.forEach(relativeSource => {
const filePath = path.join(themePath, relativeSource);
const fileName = fileToPath(relativeSource);
@ -31,4 +34,4 @@ module.exports = async function loadTheme(themePath) {
});
return alias;
};
}

View file

@ -0,0 +1,20 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {themeAlias, Alias} from './alias';
export {Alias} from './alias';
export function loadThemeAlias(themePaths: string[]): Alias {
return themePaths.reduce(
(alias, themePath) => ({
...alias,
...themeAlias(themePath),
}),
{},
);
}

View file

@ -1,28 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {validate} from 'webpack';
import createBaseConfig from '../base';
import loadSetup from '../../server/load/loadSetup';
describe('webpack base config', () => {
test('simple', async () => {
console.log = jest.fn();
const props = await loadSetup('simple');
const config = createBaseConfig(props);
const errors = validate(config);
expect(errors.length).toBe(0);
});
test('custom', async () => {
console.log = jest.fn();
const props = await loadSetup('custom');
const config = createBaseConfig(props);
const errors = validate(config);
expect(errors.length).toBe(0);
});
});

View file

@ -7,8 +7,8 @@
import {validate} from 'webpack';
import createClientConfig from '../client';
import loadSetup from '../../server/load/loadSetup';
import {createClientConfig} from '../client';
import {loadSetup} from '../../server/loadSetup';
describe('webpack dev config', () => {
test('simple', async () => {

View file

@ -7,8 +7,8 @@
import {validate} from 'webpack';
import createServerConfig from '../server';
import loadSetup from '../../server/load/loadSetup';
import {createServerConfig} from '../server';
import {loadSetup} from '../../server/loadSetup';
describe('webpack production config', () => {
test('simple', async () => {

View file

@ -5,16 +5,21 @@
* LICENSE file in the root directory of this source tree.
*/
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const path = require('path');
const fs = require('fs-extra');
const {getBabelLoader, getCacheLoader, getStyleLoaders} = require('./utils');
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import path from 'path';
import fs from 'fs-extra';
import {Configuration} from 'webpack';
import {getBabelLoader, getCacheLoader, getStyleLoaders} from './utils';
import {Props} from '../server';
const CSS_REGEX = /\.css$/;
const CSS_MODULE_REGEX = /\.module\.css$/;
module.exports = function createBaseConfig(props, isServer) {
export function createBaseConfig(
props: Props,
isServer: Boolean,
): Configuration {
const {
outDir,
siteDir,
@ -96,7 +101,7 @@ module.exports = function createBaseConfig(props, isServer) {
rules: [
{
test: /\.jsx?$/,
exclude(modulePath) {
exclude: modulePath => {
// Don't transpile node_modules except any docusaurus package
return (
/node_modules/.test(modulePath) && !/docusaurus/.test(modulePath)
@ -137,4 +142,4 @@ module.exports = function createBaseConfig(props, isServer) {
}),
],
};
};
}

View file

@ -4,16 +4,18 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const WebpackNiceLog = require('webpack-nicelog');
const merge = require('webpack-merge');
const ChunkManifestPlugin = require('./plugins/ChunkManifestPlugin');
import path from 'path';
import {Configuration} from 'webpack';
import WebpackNiceLog from 'webpack-nicelog';
import merge from 'webpack-merge';
import ChunkManifestPlugin from './plugins/ChunkManifestPlugin';
const createBaseConfig = require('./base');
import {createBaseConfig} from './base';
import {Props} from '../server';
module.exports = function createClientConfig(props) {
export function createClientConfig(props: Props): Configuration {
const isProd = process.env.NODE_ENV === 'production';
const config = createBaseConfig(props);
const config = createBaseConfig(props, false);
const clientConfig = merge(config, {
entry: {
@ -40,4 +42,4 @@ module.exports = function createClientConfig(props) {
});
return clientConfig;
};
}

View file

@ -4,12 +4,13 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const pluginName = 'ChunkManifestPlugin';
const HtmlWebpackPlugin = require('html-webpack-plugin');
const fs = require('fs-extra');
const path = require('path');
const pluginName = 'ChunkManifestPlugin';
class ChunkManifestPlugin {
constructor(options) {
this.options = {

View file

@ -5,14 +5,17 @@
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
const WebpackNiceLog = require('webpack-nicelog');
const merge = require('webpack-merge');
const createBaseConfig = require('./base');
const WaitPlugin = require('./plugins/WaitPlugin');
import path from 'path';
import StaticSiteGeneratorPlugin from 'static-site-generator-webpack-plugin';
import WebpackNiceLog from 'webpack-nicelog';
import merge from 'webpack-merge';
import {Configuration} from 'webpack';
module.exports = function createServerConfig(props) {
import {createBaseConfig} from './base';
import WaitPlugin from './plugins/WaitPlugin';
import {Props} from '../server';
export function createServerConfig(props: Props): Configuration {
const {baseUrl, routesPaths, outDir} = props;
const config = createBaseConfig(props, true);
const isProd = process.env.NODE_ENV === 'production';
@ -62,4 +65,4 @@ module.exports = function createServerConfig(props) {
],
});
return serverConfig;
};
}

View file

@ -5,14 +5,20 @@
* LICENSE file in the root directory of this source tree.
*/
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const cacheLoaderVersion = require('cache-loader/package.json').version;
const merge = require('webpack-merge');
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import merge from 'webpack-merge';
import {Configuration, Loader} from 'webpack';
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
// Utility method to get style loaders
function getStyleLoaders(isServer, cssOptions = {}) {
export function getStyleLoaders(
isServer: Boolean,
cssOptions: {
[key: string]: any;
} = {},
): Loader[] {
if (isServer) {
// https://github.com/webpack-contrib/mini-css-extract-plugin/issues/90#issuecomment-380796867
return [
cssOptions.modules
? {
@ -33,11 +39,11 @@ function getStyleLoaders(isServer, cssOptions = {}) {
loader: require.resolve('css-loader'),
options: cssOptions,
},
].filter(Boolean);
].filter(Boolean) as Loader[];
return loaders;
}
function getCacheLoader(isServer, cacheOptions) {
export function getCacheLoader(isServer: Boolean, cacheOptions?: {}): Loader {
return {
loader: require.resolve('cache-loader'),
options: Object.assign(
@ -49,7 +55,7 @@ function getCacheLoader(isServer, cacheOptions) {
};
}
function getBabelLoader(isServer, babelOptions) {
export function getBabelLoader(isServer: Boolean, babelOptions?: {}): Loader {
return {
loader: require.resolve('babel-loader'),
options: Object.assign(
@ -73,7 +79,11 @@ function getBabelLoader(isServer, babelOptions) {
* @param {Boolean} isServer indicates if this is a server webpack configuration
* @returns {Object} final/ modified webpack config
*/
function applyConfigureWebpack(configureWebpack, config, isServer) {
export function applyConfigureWebpack(
configureWebpack: any,
config: Configuration,
isServer: Boolean,
): Configuration {
if (typeof configureWebpack === 'object') {
return merge(config, configureWebpack);
}
@ -92,10 +102,3 @@ function applyConfigureWebpack(configureWebpack, config, isServer) {
}
return config;
}
module.exports = {
getBabelLoader,
getCacheLoader,
getStyleLoaders,
applyConfigureWebpack,
};

View file

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"outDir": "lib",
"noImplicitAny": false,
},
}

View file

@ -4,10 +4,10 @@
"module": "commonjs",
"lib": ["es6"],
"declaration": true,
"declarationMap": true,
/* Strict Type-Checking Options */
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
@ -25,13 +25,9 @@
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
/* Advanced Options */
"resolveJsonModule": true
},
"exclude": [
"node_modules",
"**/__tests__/**/*",
"**/lib/**/*",
]
"exclude": ["node_modules", "**/__tests__/**/*", "**/lib/**/*"]
}

161
yarn.lock
View file

@ -1790,6 +1790,11 @@
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
"@types/babel__core@^7.1.0":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.1.tgz#ce9a9e5d92b7031421e1d0d74ae59f572ba48be6"
@ -1823,6 +1828,21 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/body-parser@*":
version "1.17.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
integrity sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==
dependencies:
"@types/connect" "*"
"@types/node" "*"
"@types/chalk@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba"
integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==
dependencies:
chalk "*"
"@types/cheerio@^0.22.8":
version "0.22.11"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.11.tgz#61c0facf9636d14ba5f77fc65ed8913aa845d717"
@ -1830,6 +1850,13 @@
dependencies:
"@types/node" "*"
"@types/connect@*":
version "3.4.32"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28"
integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==
dependencies:
"@types/node" "*"
"@types/escape-string-regexp@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/escape-string-regexp/-/escape-string-regexp-1.0.0.tgz#052d16d87db583b72daceae4eaabddb66954424c"
@ -1840,6 +1867,23 @@
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
"@types/express-serve-static-core@*":
version "4.16.4"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.4.tgz#56bb8be4559401d68af4a3624ae9dd3166103e60"
integrity sha512-x/8h6FHm14rPWnW2HP5likD/rsqJ3t/77OWx2PLxym0hXbeBWQmcPyHmwX+CtCQpjIfgrUdEoDFcLPwPZWiqzQ==
dependencies:
"@types/node" "*"
"@types/range-parser" "*"
"@types/express@^4.16.1":
version "4.16.1"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0"
integrity sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg==
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "*"
"@types/serve-static" "*"
"@types/fs-extra@7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c"
@ -1856,6 +1900,13 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/globby@9.1.0":
version "9.1.0"
resolved "https://registry.yarnpkg.com/@types/globby/-/globby-9.1.0.tgz#08e2cf99c64f8e45c6cfbe05e9d8ac763aca6482"
integrity sha512-9du/HCA71EBz7syHRnM4Q/u4Fbx3SyN/Uu+4Of9lyPX4A6Xi+A8VMxvx8j5/CMTfrae2Zwdwg0fAaKvKXfRbAw==
dependencies:
globby "*"
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@ -1893,6 +1944,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.129.tgz#9aaca391db126802482655c48dd79a814488202f"
integrity sha512-oYaV0eSlnOacOr7i4X1FFdH8ttSlb57gu3I9MuStIv2CYkISEY84dNHYsC3bF6sNH7qYcu1BtVrCtQ8Q4KPTfQ==
"@types/mime@*":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@ -1913,11 +1969,44 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
"@types/serve-static@*":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"
integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==
dependencies:
"@types/express-serve-static-core" "*"
"@types/mime" "*"
"@types/shelljs@^0.8.5":
version "0.8.5"
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.5.tgz#1e507b2f6d1f893269bd3e851ec24419ef9beeea"
integrity sha512-bZgjwIWu9gHCjirKJoOlLzGi5N0QgZ5t7EXEuoqyWCHTuSddURXo3FOBYDyRPNOWzZ6NbkLvZnVkn483Y/tvcQ==
dependencies:
"@types/glob" "*"
"@types/node" "*"
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
"@types/tapable@*":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==
"@types/uglify-js@*":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
dependencies:
source-map "^0.6.1"
"@types/unist@*", "@types/unist@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
@ -1940,6 +2029,24 @@
"@types/unist" "*"
"@types/vfile-message" "*"
"@types/webpack-merge@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/webpack-merge/-/webpack-merge-4.1.5.tgz#265fbee4810474860d0f4c17e0107032881eed47"
integrity sha512-cbDo592ljSHeaVe5Q39JKN6Z4vMhmo4+C3JbksOIg+kjhKQYN2keGN7dvr/i18+dughij98Qrsfn1mU9NgVoCA==
dependencies:
"@types/webpack" "*"
"@types/webpack@*", "@types/webpack@^4.4.31":
version "4.4.31"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.31.tgz#f59b9d8210cf4d2fd254fe6d1f5ba86e557867f5"
integrity sha512-WNALmv/wxy2+OoF7A5GD8BVotXnkuMHlojVWKj/neFHU3Ut2Azbu1A7Yi2Vr6eX3z+31XgR/dJ5NpX4pQZ7ieQ==
dependencies:
"@types/anymatch" "*"
"@types/node" "*"
"@types/tapable" "*"
"@types/uglify-js" "*"
source-map "^0.6.0"
"@types/yargs@^12.0.2", "@types/yargs@^12.0.9":
version "12.0.12"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916"
@ -3375,6 +3482,15 @@ ccount@^1.0.0, ccount@^1.0.3:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.4.tgz#9cf2de494ca84060a2a8d2854edd6dfb0445f386"
integrity sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==
chalk@*, chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@ -3386,15 +3502,6 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
change-case@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e"
@ -6431,6 +6538,20 @@ globals@^11.0.1, globals@^11.1.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globby@*, globby@^9.1.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
dependencies:
"@types/glob" "^7.1.1"
array-union "^1.0.2"
dir-glob "^2.2.2"
fast-glob "^2.2.6"
glob "^7.1.3"
ignore "^4.0.3"
pify "^4.0.1"
slash "^2.0.0"
globby@8.0.2, globby@^8.0.1:
version "8.0.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
@ -6455,20 +6576,6 @@ globby@^6.1.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
globby@^9.1.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
dependencies:
"@types/glob" "^7.1.1"
array-union "^1.0.2"
dir-glob "^2.2.2"
fast-glob "^2.2.6"
glob "^7.1.3"
ignore "^4.0.3"
pify "^4.0.1"
slash "^2.0.0"
globule@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
@ -13609,10 +13716,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.4.5:
version "3.4.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
typescript@^3.5.0-rc:
version "3.5.0-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.0-rc.tgz#6f1ada90c15427713f8c0f4550ef7d357ac2a5f1"
integrity sha512-8Os3bqTeHc6bf+bkPFL3O/pb09j8SbDa2LUBxTXWpZlcHUW9ziGuiEFiqMcArkbAjGLqEzshkl4zvxhb0gVPuQ==
ua-parser-js@^0.7.18:
version "0.7.19"