From 3ced940b5a0c8a86f506683f67a999fd9e621226 Mon Sep 17 00:00:00 2001 From: Jesus Rodriguez Date: Tue, 28 Mar 2017 19:29:47 +0200 Subject: [PATCH] build(aio): ability to generate plunkers --- aio/package.json | 4 +- aio/tools/examples/add-example-boilerplate.js | 1 + aio/tools/plunker-builder/builder.js | 309 ++++++++++++++++++ aio/tools/plunker-builder/embeddedPlunker.js | 34 ++ aio/tools/plunker-builder/generatePlunkers.js | 9 + aio/tools/plunker-builder/regularPlunker.js | 23 ++ .../translator/fileTranslator.js | 47 +++ .../translator/rules/indexHtml.js | 115 +++++++ .../translator/rules/systemjsConfigExtras.js | 24 ++ aio/yarn.lock | 132 +++++++- 10 files changed, 693 insertions(+), 5 deletions(-) create mode 100644 aio/tools/plunker-builder/builder.js create mode 100644 aio/tools/plunker-builder/embeddedPlunker.js create mode 100644 aio/tools/plunker-builder/generatePlunkers.js create mode 100644 aio/tools/plunker-builder/regularPlunker.js create mode 100644 aio/tools/plunker-builder/translator/fileTranslator.js create mode 100644 aio/tools/plunker-builder/translator/rules/indexHtml.js create mode 100644 aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js diff --git a/aio/package.json b/aio/package.json index d96b867730..54a5b54aee 100644 --- a/aio/package.json +++ b/aio/package.json @@ -24,7 +24,8 @@ "pre~~deploy": "yarn build", "~~deploy": "firebase deploy --message \"Commit: $TRAVIS_COMMIT\" --non-interactive --token \"$FIREBASE_TOKEN\"", "boilerplate:add": "node ./tools/examples/add-example-boilerplate add", - "boilerplate:remove": "node ./tools/examples/add-example-boilerplate remove" + "boilerplate:remove": "node ./tools/examples/add-example-boilerplate remove", + "generate-plunkers": "node ./tools/plunker-builder/generatePlunkers" }, "private": true, "dependencies": { @@ -62,6 +63,7 @@ "html": "^1.0.0", "jasmine-core": "~2.5.2", "jasmine-spec-reporter": "~3.2.0", + "jsdom": "^9.12.0", "karma": "~1.4.1", "karma-chrome-launcher": "~2.0.0", "karma-cli": "~1.0.1", diff --git a/aio/tools/examples/add-example-boilerplate.js b/aio/tools/examples/add-example-boilerplate.js index 09dafcbdce..263071415f 100644 --- a/aio/tools/examples/add-example-boilerplate.js +++ b/aio/tools/examples/add-example-boilerplate.js @@ -12,6 +12,7 @@ const EXAMPLES_TESTING_PATH = path.join(EXAMPLES_PATH, 'testing'); const files = { exampleBoilerplate: [ 'src/styles.css', + 'src/systemjs-angular-loader.js', 'src/systemjs.config.js', 'src/tsconfig.json', 'bs-config.json', diff --git a/aio/tools/plunker-builder/builder.js b/aio/tools/plunker-builder/builder.js new file mode 100644 index 0000000000..59e246024a --- /dev/null +++ b/aio/tools/plunker-builder/builder.js @@ -0,0 +1,309 @@ +'use strict'; + +// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes +var path = require('canonical-path'); +var Q = require('q'); +var _ = require('lodash'); +var jsdom = require("jsdom"); +var fs = require("fs-extra"); +var globby = require('globby'); + +var fileTranslator = require('./translator/fileTranslator'); +var indexHtmlRules = require('./translator/rules/indexHtml'); +var systemjsConfigExtrasRules = require('./translator/rules/systemjsConfigExtras'); +var regionExtractor = require('../../transforms/examples-package/services/region-parser'); + +class PlunkerBuilder { + constructor(basePath, destPath, options) { + this.basePath = basePath; + this.destPath = destPath; + this.options = options; + this.boilerplate = path.join(__dirname, '../examples/shared/boilerplate'); + this.copyrights = {}; + + this._buildCopyrightStrings(); + } + + buildPlunkers() { + this._getPlunkerFiles(); + var errFn = this.options.errFn || function(e) { console.log(e); }; + var plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); + var fileNames = globby.sync(plunkerPaths, { ignore: ['**/node_modules/**'] }); + fileNames.forEach((configFileName) => { + try { + this._buildPlunkerFrom(configFileName); + } catch (e) { + errFn(e); + } + }); + } + + _addPlunkerFiles(postData) { + this.options.addField(postData, 'systemjs.config.js', this.systemjsConfig); + this.options.addField(postData, 'systemjs-angular-loader.js', this.systemjsModulePlugin); + } + + _buildCopyrightStrings() { + var copyright = 'Copyright 2017 Google Inc. All Rights Reserved.\n' + + 'Use of this source code is governed by an MIT-style license that\n' + + 'can be found in the LICENSE file at http://angular.io/license'; + var pad = '\n\n'; + this.copyrights.jsCss = `${pad}/*\n${copyright}\n*/`; + this.copyrights.html = `${pad}`; + } + + // Build plunker from JSON configuration file (e.g., plnkr.json): + // all properties are optional + // files: string[] - array of globs - defaults to all js, ts, html, json, css and md files (with certain files removed) + // description: string - description of this plunker - defaults to the title in the index.html page. + // tags: string[] - optional array of plunker tags (for searchability) + // main: string - name of file that will become index.html in the plunker - defaults to index.html + // open: string - name of file to display within the plunker as in "open": "app/app.module.ts" + _buildPlunkerFrom(configFileName) { + // replace ending 'plnkr.json' with 'plnkr.no-link.html' to create output file name; + var outputFileName = `${this.options.plunkerFileName}.no-link.html`; + outputFileName = configFileName.replace(/plnkr\.json$/, outputFileName); + var altFileName; + if (this.destPath && this.destPath.length > 0) { + var partPath = path.dirname(path.relative(this.basePath, outputFileName)); + var altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); + } + try { + var config = this._initConfigAndCollectFileNames(configFileName); + var postData = this._createPostData(config); + this._addPlunkerFiles(postData); + var html = this._createPlunkerHtml(config, postData); + if (this.options.writeNoLink) { + fs.writeFileSync(outputFileName, html, 'utf-8'); + } + if (altFileName) { + var altDirName = path.dirname(altFileName); + fs.ensureDirSync(altDirName); + fs.writeFileSync(altFileName, html, 'utf-8'); + } + } catch (e) { + // if we fail delete the outputFile if it exists because it is an old one. + if (this._existsSync(outputFileName)) { + fs.unlinkSync(outputFileName); + } + if (altFileName && this._existsSync(altFileName)) { + fs.unlinkSync(altFileName); + } + throw e; + } + } + + _createBasePlunkerHtml(config, embedded) { + var open = ''; + + if (config.open) { + open = embedded ? `&show=${config.open}` : `&open=${config.open}`; + } + var action = `${this.options.url}${open}`; + var html = ''; + html += `
`; + + // html += '
' + // html += '
' + html += ''; + html += ''; + return html; + } + + _createPostData(config) { + var postData = {}; + config.fileNames.forEach((fileName) => { + var content; + var extn = path.extname(fileName); + if (extn == '.png') { + content = this._encodeBase64(fileName); + fileName = fileName.substr(0, fileName.length - 4) + '.base64.png' + } else if (-1 < fileName.indexOf('systemjs.config.extras')) { + content = this._getSystemjsConfigExtras(config); + } else { + content = fs.readFileSync(fileName, 'utf-8'); + } + + if (extn == '.js' || extn == '.ts' || extn == '.css') { + content = content + this.copyrights.jsCss; + } else if (extn == '.html') { + content = content + this.copyrights.html; + } + // var escapedValue = escapeHtml(content); + + var relativeFileName = path.relative(config.basePath, fileName); + + if (relativeFileName == config.main) { + relativeFileName = 'index.html'; + } + + if (relativeFileName == 'index.html') { + content = fileTranslator.translate(content, indexHtmlRules); + if (config.description == null) { + // set config.description to title from index.html + var matches = /(.*)<\/title>/.exec(content); + if (matches) { + config.description = matches[1]; + } + } + } + + if (relativeFileName == 'systemjs.config.extras.js') { + content = fileTranslator.translate(content, systemjsConfigExtrasRules); + } + + content = regionExtractor()(content, extn.substr(1)).contents; + + this.options.addField(postData, relativeFileName, content); + }); + + var tags = ['angular', 'example'].concat(config.tags || []); + tags.forEach(function(tag,ix) { + postData['tags[' + ix + ']'] = tag; + }); + + if (!this.options.embedded) { + postData.private = true; + + postData.description = "Angular Example - " + config.description; + } else { + postData.title = "Angular Example - " + config.description; + } + + // Embedded needs to add more content, so if the callback is available, we call it + if (this.options.extraData) { + this.options.extraData(postData, config); + } + return postData; + } + + _createPlunkerHtml(config, postData) { + var baseHtml = this._createBasePlunkerHtml(config, this.options.embedded); + var doc = jsdom.jsdom(baseHtml); + var form = doc.querySelector('form'); + _.forEach(postData, (value, key) => { + var ele = this._htmlToElement(doc, '<input type="hidden" name="' + key + '">'); + ele.setAttribute('value', value); + form.appendChild(ele) + }); + var html = doc.documentElement.outerHTML; + + return html; + } + + _encodeBase64(file) { + // read binary data + var bitmap = fs.readFileSync(file); + // convert binary data to base64 encoded string + return Buffer(bitmap).toString('base64'); + } + + _existsSync(filename) { + try { + fs.accessSync(filename); + return true; + } catch(ex) { + return false; + } + } + + _getPlunkerFiles() { + var systemJsModulePlugin = '/src/systemjs-angular-loader.js'; + var systemJsConfigPath = '/src/systemjs.config.web.js'; + if (this.options.build) { + systemJsConfigPath = '/src/systemjs.config.web.build.js'; + } + this.systemjsConfig = fs.readFileSync(this.boilerplate + systemJsConfigPath, 'utf-8'); + this.systemjsModulePlugin = fs.readFileSync(this.boilerplate + systemJsModulePlugin, 'utf-8'); + + // Copyright already added to web versions of systemjs.config + // this.systemjsConfig += this.copyrights.jsCss; + } + + // Try to replace `systemjs.config.extras.js` with the + // `systemjs.config.extras.web.js` web version that + // should default SystemJS barrels to `.ts` files rather than `.js` files + // Example: see docs `testing`. + // HACK-O-MATIC! + _getSystemjsConfigExtras(config) { + var extras = config.basePath + '/systemjs.config.extras.js'; + var webExtras = config.basePath + '/systemjs.config.extras.web.js'; + if (this._existsSync(webExtras)) { + // console.log('** Substituted "' + webExtras + '" for "' + extras + '".'); + return fs.readFileSync(webExtras, 'utf-8'); + } else if (this._existsSync(extras)){ + console.log('** WARNING: no "' + webExtras + '" replacement for "' + extras + '".'); + return fs.readFileSync(extras, 'utf-8'); + } else { + console.log('** WARNING: no "' + extras + '" file; returning empty content.'); + return ''; + } + } + + _htmlToElement(document, html) { + var div = document.createElement('div'); + div.innerHTML = html; + return div.firstChild; + } + + _initConfigAndCollectFileNames(configFileName) { + var configDir = path.dirname(configFileName); + var configSrc = fs.readFileSync(configFileName, 'utf-8'); + try { + var config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; + config.basePath = config.basePath ? path.resolve(configDir, config.basePath) : configDir; + } catch (e) { + throw new Error(`Plunker config - unable to parse json file: ${configFileName}\n${e}`); + } + + var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; + if (config.files) { + if (config.files.length > 0) { + if (config.files[0].substr(0, 1) == '!') { + config.files = defaultIncludes.concat(config.files); + } + } + } else { + config.files = defaultIncludes; + } + var includeSpec = false; + var gpaths = config.files.map(function(fileName) { + fileName = fileName.trim(); + if (fileName.substr(0,1) == '!') { + return "!" + path.join(config.basePath, fileName.substr(1)); + } else { + includeSpec = includeSpec || /\.spec\.(ts|js)$/.test(fileName); + return path.join(config.basePath, fileName); + } + }); + + var defaultExcludes = [ + '!**/tsconfig.json', + '!**/*plnkr.*', + '!**/package.json', + '!**/example-config.json', + '!**/tslint.json', + '!**/.editorconfig', + '!**/systemjs.config.js', + '!**/wallaby.js', + '!**/karma-test-shim.js', + '!**/karma.conf.js', + // AoT related files + '!**/aot/**/*.*', + '!**/*-aot.*' + ]; + + // exclude all specs if no spec is mentioned in `files[]` + if (!includeSpec) { + defaultExcludes.push('!**/*.spec.*','!**/spec.js'); + } + + gpaths.push(...defaultExcludes); + + config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] }); + + return config; + } +} + +module.exports = PlunkerBuilder; diff --git a/aio/tools/plunker-builder/embeddedPlunker.js b/aio/tools/plunker-builder/embeddedPlunker.js new file mode 100644 index 0000000000..f1819e7f84 --- /dev/null +++ b/aio/tools/plunker-builder/embeddedPlunker.js @@ -0,0 +1,34 @@ +var PlunkerBuilder = require('./builder'); + +function buildPlunkers(basePath, destPath, options = {}) { + configureBuilder(options); + var builder = new PlunkerBuilder(basePath, destPath, options); + builder.buildPlunkers(); +} + +function configureBuilder(options) { + options.addField = addField; + options.plunkerFileName = 'eplnkr'; + options.url = 'https://embed.plnkr.co?show=preview'; + options.writeNoLink = false; + options.embedded = true; + options.extraData = extraData; +} + +function extraData(postData, config) { + postData['source[type]'] = config.description || 'Angular example'; + postData['source[url]'] = 'https://angular.io' +} + +function addField(postData, name, content) { + var encoding = 'utf8'; + if (name.split('.').pop() === 'png') { + encoding = 'base64'; + } + postData[`entries[${name}][content]`] = content; + postData[`entries[${name}][encoding]`] = encoding; +} + +module.exports = { + buildPlunkers: buildPlunkers +}; diff --git a/aio/tools/plunker-builder/generatePlunkers.js b/aio/tools/plunker-builder/generatePlunkers.js new file mode 100644 index 0000000000..b48dd51615 --- /dev/null +++ b/aio/tools/plunker-builder/generatePlunkers.js @@ -0,0 +1,9 @@ +const path = require('path'); +const regularPlunker = require('./regularPlunker'); +const embeddedPlunker = require('./embeddedPlunker'); + +const EXAMPLES_PATH = path.join(__dirname, '../../content/examples'); +const LIVE_EXAMPLES_PATH = path.join(__dirname, '../../src/content/live-examples'); + +regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH); +embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH); diff --git a/aio/tools/plunker-builder/regularPlunker.js b/aio/tools/plunker-builder/regularPlunker.js new file mode 100644 index 0000000000..6b7ad1b308 --- /dev/null +++ b/aio/tools/plunker-builder/regularPlunker.js @@ -0,0 +1,23 @@ +var PlunkerBuilder = require('./builder'); + +function buildPlunkers(basePath, destPath, options = {}) { + configureBuilder(options); + var builder = new PlunkerBuilder(basePath, destPath, options); + builder.buildPlunkers(); +} + +function configureBuilder(options) { + options.addField = addField; + options.plunkerFileName = 'plnkr'; + options.url = 'http://plnkr.co/edit/?p=preview'; + options.writeNoLink = true; + options.embedded = false; +} + +function addField(postData, name, content) { + postData[`files[${name}]`] = content; +} + +module.exports = { + buildPlunkers: buildPlunkers +}; diff --git a/aio/tools/plunker-builder/translator/fileTranslator.js b/aio/tools/plunker-builder/translator/fileTranslator.js new file mode 100644 index 0000000000..8a97ad2c53 --- /dev/null +++ b/aio/tools/plunker-builder/translator/fileTranslator.js @@ -0,0 +1,47 @@ +// var first_time = true; // DIAGNOSTIC + +function translate(html, rulesFile) { + rulesFile.rulesToApply.forEach(function(rxDatum) { + var rxRule = rulesFile.rules[rxDatum.pattern]; + // rxFrom is a rexexp + var rxFrom = rxRule.from; + if (rxDatum.from) { + var from = rxDatum.from.replace('/', '\/'); + var rxTemp = rxFrom.toString(); + rxTemp = rxTemp.replace('%tag%', from); + rxFrom = rxFromString(rxTemp); + } + // rxTo is a string + var rxTo = rxRule.to; + if (rxDatum.to) { + var to = rxDatum.to; + to = Array.isArray(to) ? to : [to]; + to = to.map(function (toItem) { + return rxTo.replace("%tag%", toItem); + }); + rxTo = to.join("\n "); + } + + /* DIAGNOSTIC + if (first_time && rxDatum.pattern === 'zone_pkg') { + first_time = false; + + console.log('zone_pkg'); + console.log(' rxFrom: '+rxFrom); + console.log(' rxTo: '+rxTo); + console.log(' replace: ' + html.replace(rxFrom, rxTo )); + } + */ + html = html.replace(rxFrom, rxTo); + }); + + return html; +} + +function rxFromString(rxString) { + var rx = /^\/(.*)\/(.*)/; + var pieces = rx.exec(rxString); + return RegExp(pieces[1], pieces[2]); +} + +module.exports = {translate: translate}; diff --git a/aio/tools/plunker-builder/translator/rules/indexHtml.js b/aio/tools/plunker-builder/translator/rules/indexHtml.js new file mode 100644 index 0000000000..68263885d1 --- /dev/null +++ b/aio/tools/plunker-builder/translator/rules/indexHtml.js @@ -0,0 +1,115 @@ +var rules = { + basehref: { + from: /<base href=".*"[/]?>/, + to: '<script>document.write(\'<base href="\' + document.location + \'" />\');</script>' + }, + angular_pkg: { + from: /src=".?node_modules\/@angular/g, + to: 'src="https://unpkg.com/@angular' + }, + script: { + from: /<script.*".*%tag%".*>.*<\/script>/, + to: '<script src="%tag%"></script>' + }, + link: { + from: '/<link rel="stylesheet" href=".*%tag%".*>/', + to: '<link rel="stylesheet" href="%tag%">' + }, + // Clear script like this: + // <script> + // System.import('app').catch(function(err){ console.error(err); }); + // </script> + system_strip_import_app: { + from: /<script>[^]?\s*System.import\('app'\)[^]*\/script>/, + to: '' + }, + system_extra_main: { + from: /main:\s*[\'|\"]index.js[\'|\"]/, + to: 'main: "index.ts"' + }, + system_extra_defaultExtension: { + from: /defaultExtension:\s*[\'|\"]js[\'|\"]/, + to: 'defaultExtension: "ts"' + }, + zone_pkg: { + from: /src=".?node_modules\/zone.js\/dist\/(.*)"/g, + to: 'src="https://unpkg.com/zone.js/dist/$1?main=browser"' + }, +}; + +var rulesToApply = [ + { + pattern: 'basehref', + }, + { + pattern: 'script', + from: 'node_modules/core-js/client/shim.min.js', + to: 'https://unpkg.com/core-js/client/shim.min.js' + }, + { + pattern: 'script', + from: 'node_modules/zone.js/dist/zone.js', + to: 'https://unpkg.com/zone.js@0.7.4?main=browser' + }, + { + pattern: 'script', + from: 'node_modules/rxjs/bundles/Rx.js', + to: 'https://unpkg.com/rxjs@5.0.1/bundles/Rx.js' + }, + { + pattern: 'script', + from: 'node_modules/systemjs/dist/system.src.js', + to: 'https://unpkg.com/systemjs@0.19.39/dist/system.src.js' + }, + { + pattern: 'script', + from: 'node_modules/angular/in-memory-web-api/web-api.js', + to: 'https://unpkg.com/angular/in-memory-web-api/web-api.js' + }, + + // Test libraries + + // Plunker recommends getting jasmine from cloudfare + // Don't upgrade to 2.5.x until following issue resolved + // https://github.com/jasmine/jasmine/issues/1231 + { + pattern: 'script', + from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', + to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js' + }, + { + pattern: 'script', + from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js', + to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.js' + }, + { + pattern: 'script', + from: 'node_modules/jasmine-core/lib/jasmine-core/boot.js', + to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js' + }, + { + pattern: 'link', + from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine.css', + to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css' + }, + { + pattern: 'angular_pkg', + }, + { + pattern: 'zone_pkg', + }, + // { + // pattern: 'system_strip_import_app', + // }, + { + pattern: 'system_extra_main' + }, + { + pattern: 'system_extra_defaultExtension' + } +]; + +module.exports = { + rules: rules, + rulesToApply: rulesToApply +}; diff --git a/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js b/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js new file mode 100644 index 0000000000..d774197eac --- /dev/null +++ b/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js @@ -0,0 +1,24 @@ +var rules = { + system_extra_main: { + from: /main:\s*[\'|\"]index.js[\'|\"]/g, + to: 'main: "index.ts"' + }, + system_extra_defaultExtension: { + from: /defaultExtension:\s*[\'|\"]js[\'|\"]/g, + to: 'defaultExtension: "ts"' + } +}; + +var rulesToApply = [ + { + pattern: 'system_extra_main' + }, + { + pattern: 'system_extra_defaultExtension' + } +]; + +module.exports = { + rules: rules, + rulesToApply: rulesToApply +}; diff --git a/aio/yarn.lock b/aio/yarn.lock index 64c323d71f..d22786bc5c 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -170,6 +170,10 @@ JSONStream@^1.2.1: jsonparse "^1.2.0" through ">=2.2.7 <3" +abab@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" + abbrev@1: version "1.1.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" @@ -187,6 +191,12 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" +acorn-globals@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" + dependencies: + acorn "^4.0.4" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -338,6 +348,10 @@ arr-flatten@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -1253,6 +1267,10 @@ 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-parser@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94" + content-type@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" @@ -1467,6 +1485,16 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" + +"cssstyle@>= 0.2.37 < 0.3.0": + version "0.2.37" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" + dependencies: + cssom "0.3.x" + csv-streamify@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/csv-streamify/-/csv-streamify-3.0.4.tgz#4cb614c57e3f299cca17b63fdcb4ad167777f47a" @@ -1954,6 +1982,17 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escodegen@^1.6.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -2018,7 +2057,7 @@ espree@^3.4.0: acorn "^5.0.1" acorn-jsx "^3.0.0" -esprima@^2.6.0: +esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -2035,6 +2074,10 @@ esrecurse@^4.1.0: estraverse "~4.1.0" object-assign "^4.0.1" +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -2787,6 +2830,12 @@ html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" +html-encoding-sniffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da" + dependencies: + whatwg-encoding "^1.0.1" + html-entities@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" @@ -2889,6 +2938,10 @@ https-proxy-agent@^1.0.0: debug "2" extend "3" +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -3361,6 +3414,30 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jsdom@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4" + dependencies: + abab "^1.0.3" + acorn "^4.0.4" + acorn-globals "^3.1.0" + array-equal "^1.0.0" + content-type-parser "^1.0.1" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.2.37 < 0.3.0" + escodegen "^1.6.1" + html-encoding-sniffer "^1.0.1" + nwmatcher ">= 1.3.9 < 2.0.0" + parse5 "^1.5.1" + request "^2.79.0" + sax "^1.2.1" + symbol-tree "^3.2.1" + tough-cookie "^2.3.2" + webidl-conversions "^4.0.0" + whatwg-encoding "^1.0.1" + whatwg-url "^4.3.0" + xml-name-validator "^2.0.1" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -4181,6 +4258,10 @@ nunjucks@^2.4.2: chokidar "^1.6.0" yargs "^3.32.0" +"nwmatcher@>= 1.3.9 < 2.0.0": + version "1.3.9" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a" + oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -4272,7 +4353,7 @@ optimist@~0.3, optimist@~0.3.5: dependencies: wordwrap "~0.0.2" -optionator@^0.8.2: +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -4378,6 +4459,10 @@ parse-json@^2.1.0, parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse5@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" + parse5@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" @@ -5304,7 +5389,7 @@ sax@0.6.x: version "0.6.1" resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" -sax@>=0.6.0, sax@~1.2.1: +sax@>=0.6.0, sax@^1.2.1, sax@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" @@ -5569,6 +5654,12 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -5824,6 +5915,10 @@ symbol-observable@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" +symbol-tree@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -5966,7 +6061,7 @@ toposort@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.3.tgz#f02cd8a74bd8be2fc0e98611c3bacb95a171869c" -tough-cookie@~2.3.0: +tough-cookie@^2.3.2, tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: @@ -5978,6 +6073,10 @@ toxic@^1.0.0: dependencies: lodash "^2.4.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -6396,6 +6495,14 @@ webdriver-manager@^12.0.1: semver "^5.3.0" xml2js "^0.4.17" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + +webidl-conversions@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0" + webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.9.0: version "1.10.1" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893" @@ -6475,6 +6582,19 @@ websocket-extensions@>=0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" +whatwg-encoding@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4" + dependencies: + iconv-lite "0.4.13" + +whatwg-url@^4.3.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5" + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + when@~3.6.x: version "3.6.4" resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" @@ -6606,6 +6726,10 @@ xml-char-classes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" +xml-name-validator@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" + xml2js@0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d"