refactored Markdown components to reduce bundle size

This commit is contained in:
Alec Merdler 2017-07-31 12:40:37 -04:00
parent 66e85ec63c
commit 8dc2a99926
16 changed files with 315 additions and 73 deletions

View file

@ -4,13 +4,15 @@
"private": true,
"version": "1.0.0",
"scripts": {
"dev": "./node_modules/.bin/karma start --browsers ChromeHeadless",
"test": "./node_modules/.bin/karma start --single-run --browsers ChromeHeadless",
"test:node": "JASMINE_CONFIG_PATH=static/test/jasmine.json ./node_modules/.bin/jasmine-ts './static/js/**/*.spec.ts'",
"e2e": "./node_modules/.bin/ts-node ./node_modules/.bin/protractor static/test/protractor.conf.ts",
"build": "NODE_ENV=production ./node_modules/.bin/webpack --progress",
"watch": "./node_modules/.bin/webpack --watch",
"lint": "./node_modules/.bin/tslint --type-check -p tsconfig.json -e **/*.spec.ts"
"dev": "karma start --browsers ChromeHeadless",
"test": "karma start --single-run --browsers ChromeHeadless",
"test:node": "JASMINE_CONFIG_PATH=static/test/jasmine.json jasmine-ts './static/js/**/*.spec.ts'",
"e2e": "ts-node protractor static/test/protractor.conf.ts",
"build": "npm run clean && NODE_ENV=production webpack --progress",
"watch": "npm run clean && webpack --watch",
"lint": "tslint --type-check -p tsconfig.json -e **/*.spec.ts",
"analyze": "NODE_ENV=production webpack --profile --json | awk '{if(NR>1)print}' > static/build/stats.json && webpack-bundle-analyzer --mode static -r static/build/report.html static/build/stats.json",
"clean": "rm -f static/build/*"
},
"repository": {
"type": "git",
@ -32,13 +34,13 @@
"d3": "^3.3.3",
"eonasdan-bootstrap-datetimepicker": "^4.17.43",
"file-saver": "^1.3.3",
"highlight.js": "^9.12.0",
"jquery": "1.12.4",
"ng-metadata": "^4.0.1",
"raven-js": "^3.1.0",
"restangular": "^1.2.0",
"rxjs": "^5.0.1",
"showdown": "^1.6.4",
"showdown-highlightjs-extension": "^0.1.2",
"underscore": "^1.5.2",
"urijs": "^1.18.10",
"zeroclipboard": "^2.3.0"
@ -75,6 +77,7 @@
"ts-node": "^3.0.6",
"tslint": "^5.4.3",
"typescript": "^2.2.1",
"webpack": "^2.2"
"webpack": "^2.2",
"webpack-bundle-analyzer": "^2.8.3"
}
}

View file

@ -0,0 +1,8 @@
[
"javascript",
"python",
"bash",
"nginx",
"xml",
"shell"
]

View file

@ -1,17 +0,0 @@
import { Inject } from './inject.decorator';
describe("Decorator: Inject", () => {
describe("parameter injection", () => {
it("adds given string to the 'inject' property of the annotated class", () => {
expect(ValidService.$inject).toContain('$scope');
});
});
});
class ValidService {
constructor(@Inject('$scope') private $scope: any) {}
}

View file

@ -1,11 +0,0 @@
/**
* Adds the given value to the inject property of the annotated class.
* Used to annotate the constructor parameters of an AngularJS service/component class.
* @param value The string name of the dependency.
*/
export function Inject(value: string) {
return (target: any, propertyKey: string | symbol, parameterIndex: number): void => {
target.$inject = target.$inject = [];
target.$inject[parameterIndex] = value;
};
}

View file

@ -8,15 +8,27 @@ describe("MarkdownEditorComponent", () => {
var component: MarkdownEditorComponent;
var textarea: Mock<ng.IAugmentedJQuery | any>;
var documentMock: Mock<HTMLElement & Document>;
var $windowMock: Mock<ng.IWindowService>;
beforeEach(() => {
textarea = new Mock<ng.IAugmentedJQuery | any>();
documentMock = new Mock<HTMLElement & Document>();
$windowMock = new Mock<ng.IWindowService>();
const $documentMock: any = [documentMock.Object];
component = new MarkdownEditorComponent($documentMock, 'chrome');
component = new MarkdownEditorComponent($documentMock, $windowMock.Object, 'chrome');
component.textarea = textarea.Object;
});
describe("onBeforeUnload", () => {
it("returns false to alert user about losing current changes", () => {
component.changeEditMode("write");
const allow: boolean = component.onBeforeUnload();
expect(allow).toBe(false);
});
});
describe("changeEditMode", () => {
it("sets component's edit mode to given mode", () => {

View file

@ -1,4 +1,4 @@
import { Component, Inject, Input, Output, EventEmitter, ViewChild } from 'ng-metadata/core';
import { Component, Inject, Input, Output, EventEmitter, ViewChild, HostListener } from 'ng-metadata/core';
import { MarkdownSymbol } from '../../../types/common.types';
import { BrowserPlatform } from '../../../constants/platform.constant';
import './markdown-editor.component.css';
@ -14,6 +14,7 @@ import './markdown-editor.component.css';
export class MarkdownEditorComponent {
@Input('<') public content: string;
@Output() public save: EventEmitter<{editedContent: string}> = new EventEmitter();
@Output() public discard: EventEmitter<any> = new EventEmitter();
@ -23,8 +24,14 @@ export class MarkdownEditorComponent {
private editMode: EditMode = "write";
constructor(@Inject('$document') private $document: ng.IDocumentService,
@Inject('$window') private $window: ng.IWindowService,
@Inject('BrowserPlatform') private browserPlatform: BrowserPlatform) {
this.$window.onbeforeunload = this.onBeforeUnload.bind(this);
}
@HostListener('window:beforeunload', [])
public onBeforeUnload(): boolean {
return false;
}
public changeEditMode(newMode: EditMode): void {

View file

@ -14,7 +14,9 @@ export class MarkdownInputComponent {
@Input('<') public content: string;
@Input('<') public canWrite: boolean;
@Input('@') public fieldTitle: string;
@Output() public contentChanged: EventEmitter<{content: string}> = new EventEmitter();
private isEditing: boolean = false;
public editContent(): void {

View file

@ -15,9 +15,7 @@ describe("MarkdownViewComponent", () => {
markdownConverterMock = new Mock<Converter>();
$sceMock = new Mock<ng.ISCEService>();
$sanitizeMock = jasmine.createSpy('$sanitizeSpy').and.callFake((html: string) => html);
component = new MarkdownViewComponent((options: ConverterOptions) => markdownConverterMock.Object,
$sceMock.Object,
$sanitizeMock);
component = new MarkdownViewComponent(markdownConverterMock.Object, $sceMock.Object, $sanitizeMock);
});
describe("ngOnChanges", () => {

View file

@ -1,7 +1,5 @@
import { Component, Input, Inject, OnChanges, SimpleChanges } from 'ng-metadata/core';
import { Converter, ConverterOptions } from 'showdown';
import 'showdown-highlightjs-extension';
import 'highlightjs/styles/vs.css';
import './markdown-view.component.css';
@ -17,15 +15,15 @@ export class MarkdownViewComponent implements OnChanges {
@Input('<') public content: string;
@Input('<') public firstLineOnly: boolean = false;
@Input('<') public placeholderNeeded: boolean = false;
private convertedHTML: string = '';
private readonly placeholder: string = `<p style="visibility:hidden">placeholder</p>`;
private readonly markdownChars: string[] = ['#', '-', '>', '`'];
private markdownConverter: Converter;
constructor(@Inject('markdownConverterFactory') private makeConverter: (options?: ConverterOptions) => Converter,
constructor(@Inject('markdownConverter') private markdownConverter: Converter,
@Inject('$sce') private $sce: ng.ISCEService,
@Inject('$sanitize') private $sanitize: ng.sanitize.ISanitizeService) {
this.markdownConverter = makeConverter({extensions: ['highlightjs']});
}
public ngOnChanges(changes: SimpleChanges): void {

View file

@ -0,0 +1,72 @@
import { NgModule } from 'ng-metadata/core';
import { Converter, ConverterOptions } from 'showdown';
import * as showdown from 'showdown';
import { registerLanguage, highlightAuto } from 'highlight.js/lib/highlight';
import 'highlight.js/styles/vs.css';
const highlightedLanguages: string[] = require('../../../constants/highlighted-languages.constant.json');
/**
* Dynamically fetch and register a new language with Highlight.js
*/
export const addHighlightedLanguage = (language: string): Promise<{}> => {
return new Promise((resolve, reject) => {
try {
// TODO(alecmerdler): Use `import()` here instead of `require()`
const langModule = require(`highlight.js/lib/languages/${language}`);
registerLanguage(language, langModule);
resolve();
} catch (error) {
console.log(`Language ${language} not supported for syntax highlighting`);
reject(error);
}
});
};
/**
* Showdown JS extension for syntax highlighting using Highlight.js
*/
export const showdownHighlight = (): showdown.FilterExtension => {
const htmlunencode = (text: string) => {
return (text
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>'));
};
const left = '<pre><code\\b[^>]*>';
const right = '</code></pre>';
const flags = 'g';
const replacement = (wholeMatch: string, match: string, leftSide: string, rightSide: string) => {
// TODO(alecmerdler): Call `addHighlightedLanguage` to load new languages that are detected using code-splitting
match = htmlunencode(match);
return leftSide + highlightAuto(match).value + rightSide;
};
return {
type: 'output',
filter: (text, converter, options) => {
return (<any>showdown).helper.replaceRecursiveRegExp(text, replacement, left, right, flags);
}
};
};
// Dynamically import syntax-highlighting supported languages
highlightedLanguages.forEach((langName) => addHighlightedLanguage(langName));
/**
* Markdown editor and view module.
*/
@NgModule({
imports: [],
declarations: [],
providers: [
{provide: 'markdownConverter', useValue: new Converter({extensions: [<any>showdownHighlight]})},
],
})
export class MarkdownModule {
}

View file

@ -4,6 +4,7 @@ import { QuayModule } from './quay.module';
import { provideRun } from './quay-run';
import * as angular from 'angular';
// Load all JS/CSS files into bundle: http://stackoverflow.com/a/30652110
declare var require: any;
function requireAll(r) {

View file

@ -37,7 +37,7 @@ import { ManageTriggerComponent } from './directives/ui/manage-trigger/manage-tr
import { ClipboardCopyDirective } from './directives/ui/clipboard-copy/clipboard-copy.directive';
import { CorTabsModule } from './directives/ui/cor-tabs/cor-tabs.module';
import { TriggerDescriptionComponent } from './directives/ui/trigger-description/trigger-description.component';
import { Converter, ConverterOptions } from 'showdown';
import { MarkdownModule } from './directives/ui/markdown/markdown.module';
import * as Clipboard from 'clipboard';
@ -49,6 +49,7 @@ import * as Clipboard from 'clipboard';
QuayRoutesModule,
QuayConfigModule,
CorTabsModule,
MarkdownModule,
],
declarations: [
RegexMatchViewComponent,
@ -86,7 +87,6 @@ import * as Clipboard from 'clipboard';
DockerfileServiceImpl,
DataFileServiceImpl,
{provide: 'fileReaderFactory', useValue: () => new FileReader()},
{provide: 'markdownConverterFactory', useValue: (options?: ConverterOptions) => new Converter(options)},
{provide: 'BrowserPlatform', useValue: browserPlatform},
{provide: 'clipboardFactory', useValue: (trigger, options) => new Clipboard(trigger, options)},
],

View file

@ -1,8 +1,8 @@
/**
* Service which exposes various utility methods.
*/
angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFactory',
function($sanitize, markdownConverterFactory) {
angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverter',
function($sanitize, markdownConverter) {
var utilService = {};
var adBlockEnabled = null;
@ -34,7 +34,7 @@ angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFa
};
utilService.getMarkedDown = function(string) {
return markdownConverterFactory().makeHtml(string || '');
return markdownConverter.makeHtml(string || '');
};
utilService.getFirstMarkdownLineAsText = function(commentString, placeholderNeeded) {

Binary file not shown.

View file

@ -1,17 +1,16 @@
var webpack = require('webpack');
var path = require("path");
const webpack = require('webpack');
const path = require('path');
const highlightedLanguages = require('./static/js/constants/highlighted-languages.constant.json');
var config = {
let config = {
entry: "./static/js/main.ts",
output: {
path: path.resolve(__dirname, "static/build"),
filename: 'quay-frontend.js'
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".scss"],
alias: {
sass: path.resolve(__dirname, 'static/css/directives/components/pages/')
}
extensions: [".ts", ".js"],
},
// Use global variables to maintain compatibility with non-Webpack components
externals: {
@ -48,6 +47,10 @@ var config = {
angular: "angular",
$: "jquery",
}),
// Whitelist highlight-supported languages (based on https://bjacobel.com/2016/12/04/highlight-bundle-size/)
new webpack.ContextReplacementPlugin(
/highlight\.js\/lib\/languages$/,
new RegExp(`^./(${highlightedLanguages.join('|')})$`)),
],
devtool: "cheap-module-source-map",
};

194
yarn.lock
View file

@ -70,7 +70,7 @@ abbrev@1, abbrev@1.0.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
accepts@1.3.3:
accepts@1.3.3, accepts@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
dependencies:
@ -87,6 +87,10 @@ acorn@^4.0.3, acorn@^4.0.4:
version "4.0.11"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
acorn@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75"
adm-zip@0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736"
@ -207,6 +211,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-slice@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
@ -779,10 +787,18 @@ constants-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
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.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed"
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"
@ -1016,6 +1032,10 @@ des.js@^1.0.0:
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"
di@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
@ -1045,6 +1065,10 @@ domain-browser@^1.1.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
@ -1055,6 +1079,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.6:
version "2.5.7"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a"
electron-to-chromium@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
@ -1210,6 +1238,10 @@ esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
etag@~1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
eventemitter3@1.x.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
@ -1255,6 +1287,39 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
express@^4.15.2:
version "4.15.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662"
dependencies:
accepts "~1.3.3"
array-flatten "1.1.1"
content-disposition "0.5.2"
content-type "~1.0.2"
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.7"
depd "~1.1.0"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
finalhandler "~1.0.3"
fresh "0.5.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.1"
path-to-regexp "0.1.7"
proxy-addr "~1.1.4"
qs "6.4.0"
range-parser "~1.2.0"
send "0.15.3"
serve-static "1.12.3"
setprototypeof "1.0.3"
statuses "~1.3.1"
type-is "~1.6.15"
utils-merge "1.0.0"
vary "~1.1.1"
extend@3, extend@^3.0.0, extend@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
@ -1285,6 +1350,10 @@ filename-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
filesize@^3.5.9:
version "3.5.10"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f"
fill-range@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
@ -1295,7 +1364,7 @@ fill-range@^2.1.0:
repeat-element "^1.1.2"
repeat-string "^1.5.2"
finalhandler@1.0.3:
finalhandler@1.0.3, finalhandler@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
dependencies:
@ -1340,6 +1409,14 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
forwarded@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
fresh@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
fs-access@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a"
@ -1474,6 +1551,12 @@ graceful-fs@^4.1.2:
version "1.0.1"
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
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.1:
version "4.0.6"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
@ -1542,9 +1625,9 @@ he@1.1.x:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
highlightjs@^9.8.0:
version "9.10.0"
resolved "https://registry.yarnpkg.com/highlightjs/-/highlightjs-9.10.0.tgz#fca9b78ddaa3b1abca89d6c3ee105ad270a80190"
highlight.js@^9.12.0:
version "9.12.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
hmac-drbg@^1.0.0:
version "1.0.0"
@ -1678,6 +1761,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.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
@ -2118,7 +2205,7 @@ lodash@^3.8.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.5.0, lodash@~4.17.0:
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.5.0, lodash@~4.17.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@ -2194,6 +2281,14 @@ meow@^3.3.0:
redent "^1.0.0"
trim-newlines "^1.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"
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
micromatch@^2.1.5:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
@ -2229,7 +2324,7 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7:
dependencies:
mime-db "~1.27.0"
mime@^1.3.4:
mime@1.3.4, mime@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
@ -2456,6 +2551,10 @@ once@~1.3.3:
dependencies:
wrappy "1"
opener@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
optimist@^0.6.1, optimist@~0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
@ -2571,6 +2670,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-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@ -2881,6 +2984,13 @@ protractor@^5.1.2:
webdriver-js-extender "^1.0.0"
webdriver-manager "^12.0.6"
proxy-addr@~1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
dependencies:
forwarded "~0.1.0"
ipaddr.js "1.4.0"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
@ -2945,7 +3055,7 @@ randombytes@^2.0.0, randombytes@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
range-parser@^1.0.3, range-parser@^1.2.0:
range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
@ -3199,6 +3309,10 @@ safe-buffer@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
safe-buffer@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
saucelabs@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee"
@ -3254,6 +3368,33 @@ semver@~5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a"
send@0.15.3:
version "0.15.3"
resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309"
dependencies:
debug "2.6.7"
depd "~1.1.0"
destroy "~1.0.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
fresh "0.5.0"
http-errors "~1.6.1"
mime "1.3.4"
ms "2.0.0"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.3.1"
serve-static@1.12.3:
version "1.12.3"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2"
dependencies:
encodeurl "~1.0.1"
escape-html "~1.0.3"
parseurl "~1.3.1"
send "0.15.3"
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"
@ -3276,12 +3417,6 @@ sha.js@^2.3.6:
dependencies:
inherits "^2.0.1"
showdown-highlightjs-extension@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/showdown-highlightjs-extension/-/showdown-highlightjs-extension-0.1.2.tgz#0fc90190283c1ae03fc4cccce3f1be6a5a58e4ce"
dependencies:
highlightjs "^9.8.0"
showdown@^1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.6.4.tgz#056bbb654ecdb8d8643ae12d6d597893ccaf46c6"
@ -3740,6 +3875,10 @@ ultron@1.0.x:
version "1.0.2"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
ultron@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
underscore@^1.5.2:
version "1.8.3"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
@ -3819,6 +3958,10 @@ validate-npm-package-license@^3.0.1:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
vary@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
@ -3870,6 +4013,22 @@ webdriver-manager@^12.0.6:
semver "^5.3.0"
xml2js "^0.4.17"
webpack-bundle-analyzer@^2.8.3:
version "2.8.3"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.8.3.tgz#8e7b3deb3832698c24b09c84dfe5b43902a83991"
dependencies:
acorn "^5.1.1"
chalk "^1.1.3"
commander "^2.9.0"
ejs "^2.5.6"
express "^4.15.2"
filesize "^3.5.9"
gzip-size "^3.0.0"
lodash "^4.17.4"
mkdirp "^0.5.1"
opener "^1.4.3"
ws "^2.3.1"
webpack-dev-middleware@^1.0.11:
version "1.10.1"
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893"
@ -3965,6 +4124,13 @@ ws@1.1.2, ws@^1.0.1:
options ">=0.0.5"
ultron "1.0.x"
ws@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80"
dependencies:
safe-buffer "~5.0.1"
ultron "~1.1.0"
wtf-8@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"