8
0
Просмотр исходного кода

Merge pull request #1685 from ckeditor/t/umberto/749

Internal: Adjusted `SnippetAdapter` to changes in Umberto. Improved the whitelisted-snippet option that has been renamed to `--snippets`.

Now it understands glob patterns. `--snippets=examples/**`, will build all snippets that starting with examples/. You can specify more than single glob pattern: `--snippets=framework/tutorials/*, examples/bootstrap-ui`.
Piotrek Koszuliński 6 лет назад
Родитель
Сommit
d9c3594786
4 измененных файлов с 376 добавлено и 104 удалено
  1. 2 1
      package.json
  2. 4 4
      scripts/docs/build-docs.js
  3. 308 58
      scripts/docs/snippetadapter.js
  4. 62 41
      yarn.lock

+ 2 - 1
package.json

@@ -85,11 +85,12 @@
     "mini-css-extract-plugin": "^0.4.0",
     "minimatch": "^3.0.4",
     "postcss-loader": "^3.0.0",
+    "progress-bar-webpack-plugin": "^1.12.1",
     "raw-loader": "^1.0.0",
     "style-loader": "^0.23.0",
     "svgo": "^1.1.0",
     "uglifyjs-webpack-plugin": "^1.2.7",
-    "umberto": "^0.23.1",
+    "umberto": "^1.0.0",
     "webpack": "^4.15.0"
   },
   "engines": {

+ 4 - 4
scripts/docs/build-docs.js

@@ -17,7 +17,7 @@ const skipValidation = process.argv.includes( '--skip-validation' );
 const production = process.argv.includes( '--production' );
 const watch = process.argv.includes( '--watch' );
 const verbose = process.argv.includes( '--verbose' );
-const whitelistedSnippets = process.argv.find( item => item.startsWith( '--whitelisted-snippet=' ) );
+const whitelistedSnippets = process.argv.find( item => item.startsWith( '--snippets=' ) );
 
 buildDocs();
 
@@ -53,11 +53,11 @@ function runUmberto( options ) {
 		skipLiveSnippets: options.skipLiveSnippets,
 		skipValidation: options.skipValidation,
 		snippetOptions: {
-			production: options.production
+			production: options.production,
+			whitelistedSnippets: whitelistedSnippets ? whitelistedSnippets.replace( '--snippets=', '' ).split( ',' ) : []
 		},
 		skipApi: options.skipApi,
 		verbose: options.verbose,
-		watch: options.watch,
-		whitelistedSnippets: whitelistedSnippets ? whitelistedSnippets.replace( '--whitelisted-snippet=', '' ) : undefined
+		watch: options.watch
 	} );
 }

+ 308 - 58
scripts/docs/snippetadapter.js

@@ -7,83 +7,249 @@
 
 const path = require( 'path' );
 const fs = require( 'fs' );
+const minimatch = require( 'minimatch' );
 const webpack = require( 'webpack' );
 const { bundler, styles } = require( '@ckeditor/ckeditor5-dev-utils' );
 const CKEditorWebpackPlugin = require( '@ckeditor/ckeditor5-dev-webpack-plugin' );
 const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
 const UglifyJsWebpackPlugin = require( 'uglifyjs-webpack-plugin' );
+const ProgressBarPlugin = require( 'progress-bar-webpack-plugin' );
 
-const webpackProcesses = new Map();
+const DEFAULT_LANGUAGE = 'en';
 
-module.exports = function snippetAdapter( data ) {
-	if ( !data.snippetSource.js ) {
-		throw new Error( `Missing snippet source for "${ data.snippetPath }".` );
+/**
+ * @param {Set.<Snippet>} snippets Snippet collection extracted from documentation files.
+ * @param {Object} options
+ * @param {Boolean} options.production Whether to build snippets in production mode.
+ * @param {Array.<String>|undefined} options.whitelistedSnippets An array that contains glob patterns.
+ * @param {Object.<String, Function>} umbertoHelpers
+ * @returns {Promise}
+ */
+module.exports = function snippetAdapter( snippets, options, umbertoHelpers ) {
+	const { getSnippetPlaceholder, getSnippetSourcePaths } = umbertoHelpers;
+	const snippetsDependencies = new Map();
+
+	// For each snippet, load its config. If the snippet has defined dependencies, load those as well.
+	for ( const snippetData of snippets ) {
+		if ( !snippetData.snippetSources.js ) {
+			throw new Error( `Missing snippet source for "${ snippetData.snippetName }".` );
+		}
+
+		snippetData.snippetConfig = readSnippetConfig( snippetData.snippetSources.js );
+		snippetData.snippetConfig.language = snippetData.snippetConfig.language || DEFAULT_LANGUAGE;
+
+		// If, in order to work, a snippet requires another snippet to be built, and the other snippet
+		// isn't included in any guide via `{@snippet ...}`, then that other snippet need to be marked
+		// as a dependency of the first one. Example – bootstrap UI uses an iframe, and inside that iframe we
+		// need a JS file. That JS file needs to be built, even though it's not a real snippet (and it's not used
+		// via {@snippet}).
+		if ( snippetData.snippetConfig.dependencies ) {
+			for ( const dependencyName of snippetData.snippetConfig.dependencies ) {
+				// Do not load the same dependency more than once.
+				if ( snippetsDependencies.has( dependencyName ) ) {
+					continue;
+				}
+
+				// Find a root path where to look for the snippet's sources. We just want to pass it through Webpack.
+				const snippetBasePathRegExp = new RegExp( snippetData.snippetName.replace( /\//g, '\\/' ) + '.*$' );
+				const snippetBasePath = snippetData.snippetSources.js.replace( snippetBasePathRegExp, '' );
+
+				const dependencySnippet = {
+					snippetSources: getSnippetSourcePaths( snippetBasePath, dependencyName ),
+					snippetName: dependencyName,
+					outputPath: snippetData.outputPath,
+					destinationPath: snippetData.destinationPath,
+					requiredFor: snippetData
+				};
+
+				if ( !dependencySnippet.snippetSources.js ) {
+					throw new Error( `Missing snippet source for "${ dependencySnippet.snippetName }".` );
+				}
+
+				dependencySnippet.snippetConfig = readSnippetConfig( dependencySnippet.snippetSources.js );
+				dependencySnippet.snippetConfig.language = dependencySnippet.snippetConfig.language || DEFAULT_LANGUAGE;
+
+				snippetsDependencies.set( dependencyName, dependencySnippet );
+			}
+		}
 	}
 
-	const snippetConfig = readSnippetConfig( data.snippetSource.js );
-	const outputPath = path.join( data.outputPath, data.snippetPath );
+	// Add all dependencies to the snippet collection.
+	for ( const snippetData of snippetsDependencies.values() ) {
+		snippets.add( snippetData );
+	}
 
-	const webpackConfig = getWebpackConfig( {
-		entry: data.snippetSource.js,
-		outputPath,
-		language: snippetConfig.language,
-		production: data.options.production,
-		definitions: data.options.definitions || {}
-	} );
+	// Remove snippets that do not match to patterns specified in `options.whitelistedSnippets`.
+	if ( options.whitelistedSnippets ) {
+		filterWhitelistedSnippets( snippets, options.whitelistedSnippets );
+	}
+
+	console.log( `Building ${ snippets.size } snippets...` );
+
+	const groupedSnippetsByLanguage = {};
+
+	// Group snippets by language. There is no way to build different languages in a single Webpack process.
+	// Webpack must be called as many times as different languages are being used in snippets.
+	for ( const snippetData of snippets ) {
+		if ( !groupedSnippetsByLanguage[ snippetData.snippetConfig.language ] ) {
+			groupedSnippetsByLanguage[ snippetData.snippetConfig.language ] = new Set();
+		}
+
+		groupedSnippetsByLanguage[ snippetData.snippetConfig.language ].add( snippetData );
+	}
+
+	// For each language prepare own Webpack configuration.
+	const webpackConfigs = Object.keys( groupedSnippetsByLanguage )
+		.map( language => {
+			return getWebpackConfig( groupedSnippetsByLanguage[ language ], {
+				language,
+				production: options.production,
+				definitions: options.definitions || {}
+			} );
+		} );
 
-	let promise;
+	let promise = Promise.resolve();
 
-	// See #530.
-	if ( webpackProcesses.has( outputPath ) ) {
-		promise = webpackProcesses.get( outputPath );
-	} else {
-		promise = runWebpack( webpackConfig );
-		webpackProcesses.set( outputPath, promise );
+	// Nothing to build.
+	if ( !webpackConfigs.length ) {
+		return promise;
+	}
+
+	for ( const config of webpackConfigs ) {
+		promise = promise.then( () => runWebpack( config ) );
 	}
 
 	return promise
 		.then( () => {
-			const wasCSSGenerated = fs.existsSync( path.join( outputPath, 'snippet.css' ) );
-			const cssFiles = [
-				path.join( data.basePath, 'assets', 'snippet-styles.css' )
-			];
-
-			// CSS may not be generated by Webpack if a snippet's JS file didn't import any SCSS files.
-			if ( wasCSSGenerated ) {
-				cssFiles.unshift( path.join( data.relativeOutputPath, data.snippetPath, 'snippet.css' ) );
+			// Group snippets by destination path in order to attach required HTML code and assets (CSS and JS).
+			const groupedSnippetsByDestinationPath = {};
+
+			for ( const snippetData of snippets ) {
+				if ( !groupedSnippetsByDestinationPath[ snippetData.destinationPath ] ) {
+					groupedSnippetsByDestinationPath[ snippetData.destinationPath ] = new Set();
+				}
+
+				groupedSnippetsByDestinationPath[ snippetData.destinationPath ].add( snippetData );
 			}
 
-			// If the snippet is a dependency of a parent snippet, append JS and CSS to HTML and save to disk.
-			if ( data.isDependency ) {
-				let htmlFile = fs.readFileSync( data.snippetSource.html ).toString();
+			// For every page that contains at least one snippet, we need to replace Umberto comments with HTML code.
+			for ( const destinationPath of Object.keys( groupedSnippetsByDestinationPath ) ) {
+				const snippetsOnPage = groupedSnippetsByDestinationPath[ destinationPath ];
+
+				// Assets required for the all snippets.
+				const cssFiles = [];
+				const jsFiles = [];
+
+				let content = fs.readFileSync( destinationPath ).toString();
+
+				for ( const snippetData of snippetsOnPage ) {
+					// CSS may not be generated by Webpack if a snippet's JS file didn't import any CSS files.
+					const wasCSSGenerated = fs.existsSync( path.join( snippetData.outputPath, snippetData.snippetName, 'snippet.css' ) );
+
+					// If the snippet is a dependency, append JS and CSS to HTML, save to disk and continue.
+					if ( snippetData.requiredFor ) {
+						let htmlFile = fs.readFileSync( snippetData.snippetSources.html ).toString();
+
+						if ( wasCSSGenerated ) {
+							htmlFile += '<link rel="stylesheet" href="snippet.css" type="text/css">';
+						}
+
+						htmlFile += '<script src="snippet.js"></script>';
 
-				if ( wasCSSGenerated ) {
-					htmlFile += '<link rel="stylesheet" href="snippet.css" type="text/css">';
+						fs.writeFileSync( path.join( snippetData.outputPath, snippetData.snippetName, 'snippet.html' ), htmlFile );
+
+						continue;
+					}
+
+					let snippetHTML = fs.readFileSync( snippetData.snippetSources.html ).toString();
+
+					snippetHTML = snippetHTML.replace( /%BASE_PATH%/g, snippetData.basePath );
+					snippetHTML = `<div class="live-snippet">${ snippetHTML }</div>`;
+
+					content = content.replace( getSnippetPlaceholder( snippetData.snippetName ), snippetHTML );
+
+					jsFiles.push( path.join( snippetData.basePath, 'assets', 'snippet.js' ) );
+					jsFiles.push( path.join( snippetData.relativeOutputPath, snippetData.snippetName, 'snippet.js' ) );
+
+					cssFiles.push( path.join( snippetData.basePath, 'assets', 'snippet-styles.css' ) );
+
+					if ( wasCSSGenerated ) {
+						cssFiles.unshift( path.join( snippetData.relativeOutputPath, snippetData.snippetName, 'snippet.css' ) );
+					}
 				}
 
-				htmlFile += '<script src="snippet.js"></script>';
+				const cssImportsHTML = getHTMLImports( cssFiles, importPath => {
+					return `    <link rel="stylesheet" href="${ importPath }" type="text/css">`;
+				} );
 
-				fs.writeFileSync( path.join( outputPath, 'snippet.html' ), htmlFile );
-			}
+				const jsImportsHTML = getHTMLImports( jsFiles, importPath => {
+					return `    <script src="${ importPath }"></script>`;
+				} );
 
-			return {
-				html: fs.readFileSync( data.snippetSource.html ),
-				assets: {
-					js: [
-						// Load snippet helpers first.
-						path.join( data.basePath, 'assets', 'snippet.js' ),
-
-						// Then load the actual snippet code.
-						path.join( data.relativeOutputPath, data.snippetPath, 'snippet.js' )
-					],
-					css: cssFiles
-				},
-				dependencies: snippetConfig.dependencies
-			};
+				content = content.replace( '<!--UMBERTO: SNIPPET: CSS-->', cssImportsHTML );
+				content = content.replace( '<!--UMBERTO: SNIPPET: JS-->', jsImportsHTML );
+
+				fs.writeFileSync( destinationPath, content );
+			}
+		} )
+		.then( () => {
+			console.log( `Finished building ${ snippets.size } snippets.` );
 		} );
 };
 
-function getWebpackConfig( config ) {
+/**
+ * Removes snippets that names do not match to patterns specified in `whitelistedSnippets` array.
+ *
+ * @param {Set.<Snippet>} snippets Snippet collection extracted from documentation files.
+ * @param {Array.<String>|undefined} whitelistedSnippets Snippet patterns that should be built.
+ */
+function filterWhitelistedSnippets( snippets, whitelistedSnippets ) {
+	if ( !whitelistedSnippets.length ) {
+		return;
+	}
+
+	const snippetsToBuild = new Set();
+
+	// Find all snippets that matched to specified criteria.
+	for ( const snippetData of snippets ) {
+		const matchToPatterns = whitelistedSnippets.some( pattern => minimatch( snippetData.snippetName, pattern ) );
+
+		// Snippet should be built.
+		if ( matchToPatterns ) {
+			snippetsToBuild.add( snippetData );
+		}
+	}
+
+	// Find all dependencies that are required for whitelisted snippets.
+	for ( const snippetData of snippets ) {
+		if ( snippetsToBuild.has( snippetData ) ) {
+			continue;
+		}
+
+		if ( snippetData.requiredFor && snippetsToBuild.has( snippetData.requiredFor ) ) {
+			snippetsToBuild.add( snippetData );
+		}
+	}
+
+	// Remove snippets that won't be built and aren't dependencies of other snippets.
+	for ( const snippetData of snippets ) {
+		if ( !snippetsToBuild.has( snippetData ) ) {
+			snippets.delete( snippetData );
+		}
+	}
+}
+
+/**
+ * Prepares configuration for Webpack.
+ *
+ * @param {Set.<Snippet>} snippets Snippet collection extracted from documentation files.
+ * @param {Object} config
+ * @param {String} config.language Language for the build.
+ * @param {Boolean} config.production Whether to build for production.
+ * @param {Object} config.definitions
+ * @returns {Object}
+ */
+function getWebpackConfig( snippets, config ) {
 	// Stringify all definitions values. The `DefinePlugin` injects definition values as they are so we need to stringify them,
 	// so they will become real strings in the generated code. See https://webpack.js.org/plugins/define-plugin/ for more information.
 	const definitions = {};
@@ -92,16 +258,15 @@ function getWebpackConfig( config ) {
 		definitions[ definitionKey ] = JSON.stringify( config.definitions[ definitionKey ] );
 	}
 
-	return {
+	const webpackConfig = {
 		mode: config.production ? 'production' : 'development',
 
 		devtool: 'source-map',
 
-		entry: config.entry,
+		entry: {},
 
 		output: {
-			path: config.outputPath,
-			filename: 'snippet.js'
+			filename: '[name]/snippet.js'
 		},
 
 		optimization: {
@@ -119,15 +284,18 @@ function getWebpackConfig( config ) {
 		},
 
 		plugins: [
-			new MiniCssExtractPlugin( { filename: 'snippet.css' } ),
+			new MiniCssExtractPlugin( { filename: '[name]/snippet.css' } ),
 			new CKEditorWebpackPlugin( {
-				language: config.language || 'en'
+				language: config.language
 			} ),
 			new webpack.BannerPlugin( {
 				banner: bundler.getLicenseBanner(),
 				raw: true
 			} ),
-			new webpack.DefinePlugin( definitions )
+			new webpack.DefinePlugin( definitions ),
+			new ProgressBarPlugin( {
+				format: `Building snippets for language "${ config.language }": :percent (:msg)`,
+			} )
 		],
 
 		// Configure the paths so building CKEditor 5 snippets work even if the script
@@ -165,8 +333,28 @@ function getWebpackConfig( config ) {
 			]
 		}
 	};
+
+	for ( const snippetData of snippets ) {
+		if ( !webpackConfig.output.path ) {
+			webpackConfig.output.path = snippetData.outputPath;
+		}
+
+		if ( webpackConfig.entry[ snippetData.snippetName ] ) {
+			continue;
+		}
+
+		webpackConfig.entry[ snippetData.snippetName ] = snippetData.snippetSources.js;
+	}
+
+	return webpackConfig;
 }
 
+/**
+ * Builds snippets.
+ *
+ * @param {Object} webpackConfig
+ * @returns {Promise}
+ */
 function runWebpack( webpackConfig ) {
 	return new Promise( ( resolve, reject ) => {
 		webpack( webpackConfig, ( err, stats ) => {
@@ -181,6 +369,9 @@ function runWebpack( webpackConfig ) {
 	} );
 }
 
+/**
+ * @returns {Array.<String>}
+ */
 function getModuleResolvePaths() {
 	return [
 		path.resolve( __dirname, '..', '..', 'node_modules' ),
@@ -188,6 +379,12 @@ function getModuleResolvePaths() {
 	];
 }
 
+/**
+ * Reads the snippet's configuration.
+ *
+ * @param {String} snippetSourcePath An absolute path to the file.
+ * @returns {Object}
+ */
 function readSnippetConfig( snippetSourcePath ) {
 	const snippetSource = fs.readFileSync( snippetSourcePath ).toString();
 
@@ -199,3 +396,56 @@ function readSnippetConfig( snippetSourcePath ) {
 
 	return JSON.parse( configSourceMatch[ 1 ] );
 }
+
+/**
+ * Removes duplicated entries specified in `files` array and map those entires using `mapFunction`.
+ *
+ * @param {Array.<String>} files Paths collection.
+ * @param {Function} mapFunction Function that should return a string.
+ * @returns {String}
+ */
+function getHTMLImports( files, mapFunction ) {
+	return [ ...new Set( files ) ]
+		.map( mapFunction )
+		.join( '\n' )
+		.replace( /^\s+/, '' );
+}
+
+/**
+ * @typedef {Object} Snippet
+ *
+ * @property {SnippetSource} snippetSources Sources of the snippet.
+ *
+ * @property {String} snippetName Name of the snippet. Defined directly after `@snippet` tag.
+ *
+ * @property {String} outputPath An absolute path where to write file produced by the `snippetAdapter`.
+ *
+ * @property {String} destinationPath An absolute path to the file where the snippet is being used.
+ *
+ * @property {SnippetConfiguration} snippetConfig={} Additional configuration of the snippet. It's being read from the snippet's source.
+ *
+ * @property {String} [basePath] Relative path from the processed file to the root of the documentation.
+ *
+ * @property {String} [relativeOutputPath] The same like `basePath` but for the output path (where processed file will be saved).
+ *
+ * @property {Snippet|undefined} [requiredFor] If the value is instance of `Snippet`, current snippet requires
+ * the snippet defined as `requiredFor` to work.
+ */
+
+/**
+ * @typedef {Object} SnippetSource
+ *
+ * @property {String} html An absolute path to the HTML sample.
+ *
+ * @property {String} css An absolute path to the CSS sample.
+ *
+ * @property {String} js An absolute path to the JS sample.
+ */
+
+/**
+ * @typedef {Object} SnippetConfiguration
+ *
+ * @property {String} [language] A language that will be used for building the editor.
+ *
+ * @property {Array.<String>} [dependencies] Names of samples that are required to working.
+ */

+ 62 - 41
yarn.lock

@@ -993,9 +993,9 @@
   integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==
 
 "@types/node@^10.1.0":
-  version "10.14.4"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5"
-  integrity sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg==
+  version "10.14.5"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.5.tgz#27733a949f5d9972d87109297cffb62207ace70f"
+  integrity sha512-Ja7d4s0qyGFxjGeDq5S7Si25OFibSAHUi6i17UWnwNnpitADN7hah9q0Tl25gxuV5R1u2Bx+np6w4LHXfHyj/g==
 
 "@types/q@^1.5.1":
   version "1.5.2"
@@ -2193,9 +2193,9 @@ caniuse-api@^3.0.0:
     lodash.uniq "^4.5.0"
 
 caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000960:
-  version "1.0.30000960"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000960.tgz#ec48297037e5607f582f246ae7b12bee66a78999"
-  integrity sha512-7nK5qs17icQaX6V3/RYrJkOsZyRNnroA4+ZwxaKJzIKy+crIy0Mz5CBlLySd2SNV+4nbUZeqeNfiaEieUBu3aA==
+  version "1.0.30000962"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000962.tgz#6c10c3ab304b89bea905e66adf98c0905088ee44"
+  integrity sha512-WXYsW38HK+6eaj5IZR16Rn91TGhU3OhbwjKZvJ4HN/XBIABLKfbij9Mnd3pM0VEwZSlltWjoWg3I8FQ0DGgNOA==
 
 caseless@~0.12.0:
   version "0.12.0"
@@ -3599,9 +3599,9 @@ ee-first@1.1.1:
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
 electron-to-chromium@^1.3.124:
-  version "1.3.124"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz#861fc0148748a11b3e5ccebdf8b795ff513fa11f"
-  integrity sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w==
+  version "1.3.125"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.125.tgz#dbde0e95e64ebe322db0eca764d951f885a5aff2"
+  integrity sha512-XxowpqQxJ4nDwUXHtVtmEhRqBpm2OnjBomZmZtHD0d2Eo0244+Ojezhk3sD/MBSSe2nxCdGQFRXHIsf/LUTL9A==
 
 elegant-spinner@^1.0.1:
   version "1.0.1"
@@ -5609,9 +5609,9 @@ is-path-cwd@^1.0.0:
   integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
 
 is-path-cwd@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.0.0.tgz#d4777a8e227a00096a31f030db3770f84b116c02"
-  integrity sha512-m5dHHzpOXEiv18JEORttBO64UgTEypx99vCxQLjbBvGhOJxnTNglYoFXxwo6AbsQb79sqqycQEHv2hWkHZAijA==
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.1.0.tgz#2e0c7e463ff5b7a0eb60852d851a6809347a124c"
+  integrity sha512-Sc5j3/YnM8tDeyCsVeKlm/0p95075DyLmDEIkSgQ7mXkrOX+uTCtmQFm0CYzVyJwcCCmO3k8qfJt17SxQwB5Zw==
 
 is-path-in-cwd@^1.0.0:
   version "1.0.1"
@@ -5621,11 +5621,11 @@ is-path-in-cwd@^1.0.0:
     is-path-inside "^1.0.0"
 
 is-path-in-cwd@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.0.0.tgz#68e452a6eec260500cec21e029c0a44cc0dcd2ea"
-  integrity sha512-6Vz5Gc9s/sDA3JBVu0FzWufm8xaBsqy1zn8Q6gmvGP6nSDMw78aS4poBNeatWjaRpTpxxLn1WOndAiOlk+qY8A==
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
+  integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
   dependencies:
-    is-path-inside "^1.0.0"
+    is-path-inside "^2.1.0"
 
 is-path-inside@^1.0.0:
   version "1.0.1"
@@ -5634,6 +5634,13 @@ is-path-inside@^1.0.0:
   dependencies:
     path-is-inside "^1.0.1"
 
+is-path-inside@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
+  integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
+  dependencies:
+    path-is-inside "^1.0.2"
+
 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"
@@ -6938,17 +6945,17 @@ miller-rabin@^4.0.0:
     bn.js "^4.0.0"
     brorand "^1.0.1"
 
-mime-db@~1.38.0:
-  version "1.38.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
-  integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
+mime-db@1.40.0:
+  version "1.40.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+  integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
 
 mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19:
-  version "2.1.22"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
-  integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
+  version "2.1.24"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+  integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
   dependencies:
-    mime-db "~1.38.0"
+    mime-db "1.40.0"
 
 mime@^2.1.0, mime@^2.3.1:
   version "2.4.2"
@@ -7099,9 +7106,9 @@ modify-values@^1.0.0:
   integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
 
 moment-timezone@^0.5.14:
-  version "0.5.23"
-  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463"
-  integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==
+  version "0.5.25"
+  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.25.tgz#a11bfa2f74e088327f2cd4c08b3e7bdf55957810"
+  integrity sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==
   dependencies:
     moment ">= 2.9.0"
 
@@ -7508,7 +7515,7 @@ object-visit@^1.0.0:
   dependencies:
     isobject "^3.0.0"
 
-object.assign@^4.0.4, object.assign@^4.1.0:
+object.assign@^4.0.1, object.assign@^4.0.4, object.assign@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
   integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
@@ -8381,6 +8388,20 @@ process@^0.11.10:
   resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
   integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
 
+progress-bar-webpack-plugin@^1.12.1:
+  version "1.12.1"
+  resolved "https://registry.yarnpkg.com/progress-bar-webpack-plugin/-/progress-bar-webpack-plugin-1.12.1.tgz#bbf3b1137a4ba2474eeb111377d6c1a580c57dd1"
+  integrity sha512-tVbPB5xBbqNwdH3mwcxzjL1r1Vrm/xGu93OsqVSAbCaXGoKFvfWIh0gpMDpn2kYsPVRSAIK0pBkP9Vfs+JJibQ==
+  dependencies:
+    chalk "^1.1.1"
+    object.assign "^4.0.1"
+    progress "^1.1.8"
+
+progress@^1.1.8:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
+  integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
+
 progress@^2.0.0:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@@ -9136,9 +9157,9 @@ run-queue@^1.0.0, run-queue@^1.0.3:
     aproba "^1.1.1"
 
 rxjs@^6.3.3, rxjs@^6.4.0:
-  version "6.4.0"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504"
-  integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==
+  version "6.5.1"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4"
+  integrity sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg==
   dependencies:
     tslib "^1.9.0"
 
@@ -10296,9 +10317,9 @@ uglify-js@^2.6.1:
     uglify-to-browserify "~1.0.0"
 
 uglify-js@^3.1.4:
-  version "3.5.4"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.4.tgz#4a64d57f590e20a898ba057f838dcdfb67a939b9"
-  integrity sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==
+  version "3.5.6"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.6.tgz#8a5f8a06ee7415ac1fa302f4623bc7344b553da4"
+  integrity sha512-YDKRX8F0Y+Jr7LhoVk0n4G7ltR3Y7qFAj+DtVBthlOgCcIj1hyMigCfousVfn9HKmvJ+qiFlLDwaHx44/e5ZKw==
   dependencies:
     commander "~2.20.0"
     source-map "~0.6.1"
@@ -10327,10 +10348,10 @@ ultron@~1.1.0:
   resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
   integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==
 
-umberto@^0.23.1:
-  version "0.23.1"
-  resolved "https://registry.yarnpkg.com/umberto/-/umberto-0.23.1.tgz#b61efe561e8645e3ab4774219da188e51ed3bb73"
-  integrity sha512-SbYOfTYkgk90R6UTNoDtqxUuKOgBcaOf9byBv9GDjfvyU7k1jR+Nn9fyNXUEAi7oO7wKEGvPHFCGPJceY4t6Rg==
+umberto@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/umberto/-/umberto-1.0.0.tgz#491d7feb17c1cf0cb88eb16cfbc610024906d7e8"
+  integrity sha512-ZT8EirP3i+D6nFsZSmst+jO5XgaZWVqnG4mXy8P+ugq5jzZIii11kFva7HQiy5WSwrqXhBAsgDTj5uoXYQyxeA==
   dependencies:
     "@babel/core" "^7.1.2"
     "@babel/polyfill" "^7.0.0"
@@ -10721,9 +10742,9 @@ watchpack@^1.5.0:
     neo-async "^2.5.0"
 
 webpack-cli@^3.0.8:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.0.tgz#55c8a74cae1e88117f9dda3a801c7272e93ca318"
-  integrity sha512-t1M7G4z5FhHKJ92WRKwZ1rtvi7rHc0NZoZRbSkol0YKl4HvcC8+DsmGDmK7MmZxHSAetHagiOsjOB6MmzC2TUw==
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.1.tgz#98b0499c7138ba9ece8898bd99c4f007db59909d"
+  integrity sha512-c2inFU7SM0IttEgF7fK6AaUsbBnORRzminvbyRKS+NlbQHVZdCtzKBlavRL5359bFsywXGRAItA5di/IruC8mg==
   dependencies:
     chalk "^2.4.1"
     cross-spawn "^6.0.5"