diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ swh/web/static/js/ swh/web/static/css/ swh/web/static/fonts/ +swh/web/static/jssources/ .cache-loader/ build/ dist/ diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "css-loader": "^2.1.0", "d3": "^5.8.2", "datatables.net-bs4": "^1.10.19", + "ejs": "^2.6.1", "eslint": "^5.14.1", "eslint-loader": "^2.1.2", "eslint-plugin-import": "^2.16.0", @@ -67,7 +68,9 @@ "resolve-url-loader": "^3.0.1", "robotstxt-webpack-plugin": "^5.0.0", "sass-loader": "^7.1.0", + "schema-utils": "^1.0.0", "showdown": "^1.9.0", + "spdx-expression-parse": "^3.0.0", "style-loader": "^0.23.1", "stylelint": "^9.10.1", "stylelint-config-standard": "^18.2.0", diff --git a/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/README.md b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/README.md new file mode 100644 --- /dev/null +++ b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/README.md @@ -0,0 +1,163 @@ +# generate-weblabels-webpack-plugin + +This plugin for webpack >= 4 enables to generate an HTML page stating the licenses of every source files bundled in the JavaScript assets generated by webpack. Such a page is called [Web Labels](https://www.gnu.org/licenses/javascript-labels.html) and is intended to be consumed by the [GNU LibreJS](https://www.gnu.org/software/librejs/) Firefox plugin whose purpose is, quoting its documentation: + +> GNU LibreJS aims to address the JavaScript problem described in Richard Stallman's article [The JavaScript Trap](http://www.gnu.org/philosophy/javascript-trap.html). LibreJS is a free add-on for GNU IceCat and other Mozilla-based browsers. It blocks nonfree nontrivial JavaScript while allowing JavaScript that is free and/or trivial. + +So, without the Web Labels page, the loading of JavaScript assets generated by webpack in client browsers will be blocked by the LibreJS Firefox plugin. Usually, most of the bundled JavaScript source files are retrieved through `npm` or `yarn` and their associated licenses are compatible with those allowed by LibreJS. If your webpack project is also released under a free license, you can use this plugin to ensure LibreJS will detect the licenses of your bundled source files and allow the loading of the webpack generated Javascript assets. + +In order to be compliant with the LibreJS specifications, the Web Labels page must contain the following information. For each JavaScript asset generated by webpack, all bundled source files in it need to be referenced along with their licenses but also a link to their non-minified source code. + +The plugin works by processing the compilation statistics available after the whole webpack processing and currently does the following: + - For each bundled JavaScript source files, it will try to find its associated LibreJS compatible license by parsing the corresponding [SPDX License Expression](https://spdx.org/licenses/) (usually located in `package.json` files) +
+ - It copies all non-minified source files, bundled into the generated JavaScript assets, into a directory located into the webpack output folder. Also if a license file can be found for a source file it will also be copied. +
+ - It generates either a Web Labels HTML page named `jslicenses.html` or a JSON file named `jslicenses.json`, into a directory located into the webpack output folder. The JSON file should then be used with an HTML template engine to generate the Web Labels page. Its structure is the following: + +```json + { + "": [ + { + "id": "", + "licenses": [ + { + "name": "", + "url": "", + "copy_url": "" + }, + ... + ] + "src_url": "" + }, + { + ... + } + ], + "": [ + ... + ], + ... + } +``` + +In order for LibreJS to consume the Web Labels, a link to it must be added in the relevant HTML pages of your web application, more details in the relevant [section](https://www.gnu.org/software/librejs/free-your-javascript.html#step3) of the LibreJS documentation. + +## Usage + +To begin, you will need to install `generate-weblabels-webpack-plugin` (**WARNING: wip, this is currently not published on the npm registry**) + +```shell +$ npm install generate-weblabels-webpack-plugin --save-dev +``` + +or + +```shell +$ yarn add generate-weblabels-webpack-plugin --dev +``` + +Then add the plugin to your webpack configuration, for example: + +```js +const GenerateWebLabelsPlugin = require('generate-weblabels-webpack-plugin'); + +module.exports = { + // ... + plugins: [ + new GenerateWebLabelsPlugin(options) + ] +}; +``` + +Also, when compiling your assets in production mode, the following webpack option must be adjusted: +```js +module.exports = { + // ... + optimization: { + concatenateModules: false + } +}; +``` +This will prevent webpack to concatenate some modules into a single one, which makes license and original source files detection impossible. + +Please also note that the plugin will not remove the previously copied Web Labels related files into the webpack output folder. You should use the [`clean-webpack-plugin`](https://github.com/johnagan/clean-webpack-plugin) to perform that task. + +## Options + +The following options can be provided + +### `outputDir` +type: `String` +default: `'jssources'` + +Specify the directory inside the webpack output folder in which the Web Labels related files will be emitted. + +### `outputType` +type: `Enum` +default: `'html'` + +Specify which type of output the plugin generates. Possible values are: + + - `'html'`: generate an HTML page named "jslicenses.html" containing the Web Labels + - `'json'`: generate a JSON file named "jslicenses.json" containing all relevant info to generate the Web Labels page through an HTML template engine. + +### `exclude` +type: `Array` +default: `[]` + +An array of module name or source file path prefixes to exclude from the plugin processing. If the prefix does not start with `./`, it is considered as a node module. +This can be used to exclude some special modules processed by webpack that do not generate any JavaScript that will be bundled in the generated assets (for instance the scripts associated to [`mini-css-extract-plugin`](https://github.com/webpack-contrib/mini-css-extract-plugin)). + +### `srcReplace` +type: `Object` +default: `{}` + +An object mapping source files to replace in the generated output. +This should be used when a node module points to its minified version by default. + +### `licenseOverride` +type: `Object` +default: `{}` + +An object mapping source files or node modules to their corresponding SPDX license expressions. +This should be used when you have source files inside your webpack project source tree with licenses different from the one of your project. It can also be used when you have a node module with an invalid SPDX license expression in its `package.json`. +This object must have the following structure: + +```json +{ + "": { + "spdxLicenseExpression": "", + "licenseFilePath": "" + }, + ... +} +``` + +The keys of this object can correspond either to a source file path relative to the webpack root folder or a node module identifier. +The path of the license file must be relative to the webpack project root folder. + +### `additionalScripts` +type: `Object` +default: `{}` + +An object declaring additional JavaScript assets loaded by your web application but not generated by webpack. It must have the following structure: + +```json +{ + "": [ + { + "id": "", + "path": "", + "spdxLicenseExpression": "", + "licenseFilePath": "" + }, + { + ... + } + ], + ... +} +``` + +The paths of the license and source files must be relative to the webpack project root folder. \ No newline at end of file diff --git a/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/index.js b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/index.js new file mode 100644 --- /dev/null +++ b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/index.js @@ -0,0 +1,367 @@ +/** + * Copyright (C) 2019 The Software Heritage developers + * See the AUTHORS file at the top-level directory of this distribution + * License: GNU Affero General Public License version 3, or any later version + * See top-level LICENSE file for more information + */ + +// This is a plugin for webpack >= 4 enabling to generate a Web Labels page intended +// to be consume by the LibreJS Firefox plugin (https://www.gnu.org/software/librejs/). +// See README.md for its complete documentation. + +const ejs = require('ejs'); +const fs = require('fs'); +const log = require('webpack-log'); +const path = require('path'); +const schema = require('./plugin-options-schema.json'); +const spdxParse = require('spdx-expression-parse'); +const spdxLicensesMapping = require('./spdx-licenses-mapping'); +const validateOptions = require('schema-utils'); + +const pluginName = 'GenerateWebLabelsPlugin'; + +class GenerateWebLabelsPlugin { + + constructor(opts) { + // check that provided options match JSON schema + validateOptions(schema, opts, pluginName); + this.options = opts || {}; + this.weblabelsDirName = this.options['outputDir'] || 'jssources'; + this.outputType = this.options['outputType'] || 'html'; + // source file extension handled by webpack and compiled to js + this.srcExts = ['js', 'ts', 'coffee', 'lua']; + this.srcExtsRegexp = new RegExp('^.*.(' + this.srcExts.join('|') + ')$'); + this.chunkNameToJsAsset = {}; + this.chunkJsAssetToSrcFiles = {}; + this.packageJsonCache = {}; + this.packageLicenseFile = {}; + this.exclude = []; + this.copiedFiles = new Set(); + this.logger = log({name: pluginName}); + // populate module prefix patterns to exclude + if (Array.isArray(this.options['exclude'])) { + this.options['exclude'].forEach(toExclude => { + if (!toExclude.startsWith('.')) { + this.exclude.push('./' + path.join('node_modules', toExclude)); + } else { + this.exclude.push(toExclude); + } + }); + } + } + + apply(compiler) { + compiler.hooks.done.tap(pluginName, statsObj => { + + // get the stats object in JSON format + let stats = statsObj.toJson(); + this.stats = stats; + + // set output folder + this.weblabelsOutputDir = path.join(stats.outputPath, this.weblabelsDirName); + this.recursiveMkdir(this.weblabelsOutputDir); + + // map each generated webpack chunk to its js asset + Object.keys(stats.assetsByChunkName).forEach((chunkName, i) => { + if (Array.isArray(stats.assetsByChunkName[chunkName])) { + for (let asset of stats.assetsByChunkName[chunkName]) { + if (asset.endsWith('.js')) { + this.chunkNameToJsAsset[chunkName] = asset; + this.chunkNameToJsAsset[i] = asset; + break; + } + } + } else if (stats.assetsByChunkName[chunkName].endsWith('.js')) { + this.chunkNameToJsAsset[chunkName] = stats.assetsByChunkName[chunkName]; + this.chunkNameToJsAsset[i] = stats.assetsByChunkName[chunkName]; + } + }); + + // iterate on all bundled webpack modules + stats.modules.forEach(mod => { + + let srcFilePath = mod.name; + + // do not process non js related modules + if (!this.srcExtsRegexp.test(srcFilePath)) { + return; + } + + // do not process modules unrelated to a source file + if (!srcFilePath.startsWith('./')) { + return; + } + + // do not process modules in the exclusion list + for (let toExclude of this.exclude) { + if (srcFilePath.startsWith(toExclude)) { + return; + } + } + + // iterate on all chunks containing the module + mod.chunks.forEach(chunk => { + + let chunkJsAsset = stats.publicPath + this.chunkNameToJsAsset[chunk]; + + // init the chunk to source files mapping if needed + if (!this.chunkJsAssetToSrcFiles.hasOwnProperty(chunkJsAsset)) { + this.chunkJsAssetToSrcFiles[chunkJsAsset] = []; + } + // check if the source file needs to be replaces + if (this.options['srcReplace'] && this.options['srcReplace'].hasOwnProperty(srcFilePath)) { + srcFilePath = this.options['srcReplace'][srcFilePath]; + } + + // init source file metadata + let srcFileData = {'id': this.cleanupPath(srcFilePath)}; + + // find and parse the corresponding package.json file + let packageJsonPath; + let nodeModule = srcFilePath.startsWith('./node_modules/'); + if (nodeModule) { + packageJsonPath = this.findPackageJsonPath(srcFilePath); + } else { + packageJsonPath = './package.json'; + } + let packageJson = this.parsePackageJson(packageJsonPath); + + // extract license information, overriding it if needed + let licenseOverridden = false; + let licenseFilePath; + if (this.options['licenseOverride']) { + for (let srcFilePrefixKey of Object.keys(this.options['licenseOverride'])) { + let srcFilePrefix = srcFilePrefixKey; + if (!srcFilePrefixKey.startsWith('.')) { + srcFilePrefix = './' + path.join('node_modules', srcFilePrefixKey); + } + if (srcFilePath.startsWith(srcFilePrefix)) { + let spdxLicenseExpression = this.options['licenseOverride'][srcFilePrefixKey]['spdxLicenseExpression']; + licenseFilePath = this.options['licenseOverride'][srcFilePrefixKey]['licenseFilePath']; + let parsedSpdxLicenses = this.parseSpdxLicenseExpression(spdxLicenseExpression, `file ${srcFilePath}`); + srcFileData['licenses'] = this.spdxToWebLabelsLicenses(parsedSpdxLicenses); + licenseOverridden = true; + break; + } + } + } + + if (!licenseOverridden) { + srcFileData['licenses'] = this.extractLicenseInformation(packageJson); + let licenseDir = path.join(...packageJsonPath.split('/').slice(0, -1)); + licenseFilePath = this.findLicenseFile(licenseDir); + } + + // copy original license file and get its url + let licenseCopyUrl = this.copyLicenseFile(licenseFilePath); + srcFileData['licenses'].forEach(license => { + license['copy_url'] = licenseCopyUrl; + }); + + // generate url for downloading non-minified source code + srcFileData['src_url'] = stats.publicPath + path.join(this.weblabelsDirName, srcFileData['id']); + + // add source file metadata to the webpack chunk + this.chunkJsAssetToSrcFiles[chunkJsAsset].push(srcFileData); + // copy non-minified source to output folder + this.copyFileToOutputPath(srcFilePath); + }); + }); + + // process additional scripts if needed + if (this.options['additionalScripts']) { + for (let script of Object.keys(this.options['additionalScripts'])) { + this.chunkJsAssetToSrcFiles[script] = []; + for (let scriptSrc of this.options['additionalScripts'][script]) { + let scriptSrcData = {'id': scriptSrc['id']}; + let licenceFilePath = scriptSrc['licenseFilePath']; + let parsedSpdxLicenses = this.parseSpdxLicenseExpression(scriptSrc['spdxLicenseExpression'], + `file ${scriptSrc['path']}`); + scriptSrcData['licenses'] = this.spdxToWebLabelsLicenses(parsedSpdxLicenses); + let licenseCopyUrl = this.copyLicenseFile(licenceFilePath); + scriptSrcData['licenses'].forEach(license => { + license['copy_url'] = licenseCopyUrl; + }); + scriptSrcData['src_url'] = stats.publicPath + path.join(this.weblabelsDirName, scriptSrc['id']); + this.chunkJsAssetToSrcFiles[script].push(scriptSrcData); + this.copyFileToOutputPath(scriptSrc['path']); + } + } + } + + if (this.outputType === 'json') { + // generate the jslicenses.json file + let weblabelsData = JSON.stringify(this.chunkJsAssetToSrcFiles); + let weblabelsJsonFile = path.join(this.weblabelsOutputDir, 'jslicenses.json'); + fs.writeFileSync(weblabelsJsonFile, weblabelsData); + } else { + // generate the jslicenses.html file + let weblabelsPageFile = path.join(this.weblabelsOutputDir, 'jslicenses.html'); + ejs.renderFile(path.join(__dirname, 'jslicenses.ejs'), + {'jslicenses_data': this.chunkJsAssetToSrcFiles}, + {'rmWhitespace': true}, + (e, str) => { + fs.writeFileSync(weblabelsPageFile, str); + }); + } + }); + } + + cleanupPath(moduleFilePath) { + return moduleFilePath.replace(/^[./]*node_modules\//, '').replace(/^.\//, ''); + } + + findPackageJsonPath(srcFilePath) { + let pathSplit = srcFilePath.split('/'); + let packageJsonPath; + for (let i = 3; i < pathSplit.length; ++i) { + packageJsonPath = path.join(...pathSplit.slice(0, i), 'package.json'); + if (fs.existsSync(packageJsonPath)) { + break; + } + } + return packageJsonPath; + } + + findLicenseFile(packageJsonDir) { + if (!this.packageLicenseFile.hasOwnProperty(packageJsonDir)) { + let foundLicenseFile; + fs.readdirSync(packageJsonDir).forEach(file => { + if (foundLicenseFile) { + return; + } + if (file.toLowerCase().startsWith('license')) { + foundLicenseFile = path.join(packageJsonDir, file); + } + }); + this.packageLicenseFile[packageJsonDir] = foundLicenseFile; + } + return this.packageLicenseFile[packageJsonDir]; + } + + copyLicenseFile(licenseFilePath) { + let licenseCopyPath = ''; + if (licenseFilePath && fs.existsSync(licenseFilePath)) { + let ext = ''; + // add a .txt extension in order to serve license file with text/plain + // content type to client browsers + if (licenseFilePath.toLowerCase().indexOf('license.') === -1) { + ext = '.txt'; + } + this.copyFileToOutputPath(licenseFilePath, ext); + licenseFilePath = this.cleanupPath(licenseFilePath); + licenseCopyPath = this.stats.publicPath + path.join(this.weblabelsDirName, licenseFilePath + ext); + } + return licenseCopyPath; + } + + parsePackageJson(packageJsonPath) { + if (!this.packageJsonCache.hasOwnProperty(packageJsonPath)) { + let packageJsonStr = fs.readFileSync(packageJsonPath).toString('utf8'); + this.packageJsonCache[packageJsonPath] = JSON.parse(packageJsonStr); + } + return this.packageJsonCache[packageJsonPath]; + } + + parseSpdxLicenseExpression(spdxLicenseExpression, context) { + let parsedLicense; + try { + parsedLicense = spdxParse(spdxLicenseExpression); + if (spdxLicenseExpression.indexOf('AND') !== -1) { + this.logger.warn(`The SPDX license expression '${spdxLicenseExpression}' associated to ${context} ` + + 'contains an AND operator, this is currently not properly handled and erroneous ' + + 'licenses information may be provided to LibreJS'); + } + } catch (e) { + this.logger.warn(`Unable to parse the SPDX license expression '${spdxLicenseExpression}' associated to ${context}.`); + this.logger.warn('Some generated JavaScript assets may be blocked by LibreJS due to missing license information.'); + parsedLicense = {'license': spdxLicenseExpression}; + } + return parsedLicense; + } + + spdxToWebLabelsLicense(spdxLicenceId) { + for (let i = 0; i < spdxLicensesMapping.length; ++i) { + if (spdxLicensesMapping[i]['spdx_ids'].indexOf(spdxLicenceId) !== -1) { + let licenseData = Object.assign({}, spdxLicensesMapping[i]); + delete licenseData['spdx_ids']; + delete licenseData['magnet_link']; + licenseData['copy_url'] = ''; + return licenseData; + } + } + this.logger.warn(`Unable to associate the SPDX license identifier '${spdxLicenceId}' to a LibreJS supported license.`); + this.logger.warn('Some generated JavaScript assets may be blocked by LibreJS due to missing license information.'); + return { + 'name': spdxLicenceId, + 'url': '', + 'copy_url': '' + }; + } + + spdxToWebLabelsLicenses(spdxLicenses) { + // This method simply extracts all referenced licenses in the SPDX expression + // regardless of their combinations. + // TODO: Handle licenses combination properly once LibreJS has a spec for it. + let ret = []; + if (spdxLicenses.hasOwnProperty('license')) { + ret.push(this.spdxToWebLabelsLicense(spdxLicenses['license'])); + } else if (spdxLicenses.hasOwnProperty('left')) { + if (spdxLicenses['left'].hasOwnProperty('license')) { + let licenseData = this.spdxToWebLabelsLicense(spdxLicenses['left']['license']); + ret.push(licenseData); + } else { + ret = ret.concat(this.spdxToWebLabelsLicenses(spdxLicenses['left'])); + } + ret = ret.concat(this.spdxToWebLabelsLicenses(spdxLicenses['right'])); + } + return ret; + } + + extractLicenseInformation(packageJson) { + let spdxLicenseExpression; + if (packageJson.hasOwnProperty('license')) { + spdxLicenseExpression = packageJson['license']; + } else if (packageJson.hasOwnProperty('licenses')) { + // for node packages using deprecated licenses property + let licenses = packageJson['licenses']; + if (Array.isArray(licenses)) { + let l = []; + licenses.forEach(license => { + l.push(license['type']); + }); + spdxLicenseExpression = l.join(' OR '); + } else { + spdxLicenseExpression = licenses['type']; + } + } + let parsedSpdxLicenses = this.parseSpdxLicenseExpression(spdxLicenseExpression, + `module ${packageJson['name']}`); + return this.spdxToWebLabelsLicenses(parsedSpdxLicenses); + } + + copyFileToOutputPath(srcFilePath, ext = '') { + if (this.copiedFiles.has(srcFilePath)) { + return; + } + let destPath = this.cleanupPath(srcFilePath); + let destDir = path.join(this.weblabelsOutputDir, ...destPath.split('/').slice(0, -1)); + this.recursiveMkdir(destDir); + destPath = path.join(this.weblabelsOutputDir, destPath + ext); + fs.copyFileSync(srcFilePath, destPath); + this.copiedFiles.add(srcFilePath); + } + + recursiveMkdir(destPath) { + let destPathSplit = destPath.split('/'); + for (let i = 1; i < destPathSplit.length; ++i) { + let currentPath = path.join('/', ...destPathSplit.slice(0, i + 1)); + if (!fs.existsSync(currentPath)) { + fs.mkdirSync(currentPath); + } + } + } + +}; + +module.exports = GenerateWebLabelsPlugin; diff --git a/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/jslicenses.ejs b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/jslicenses.ejs new file mode 100644 --- /dev/null +++ b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/jslicenses.ejs @@ -0,0 +1,81 @@ +<%# + Copyright (C) 2019 The Software Heritage developers + See the AUTHORS file at the top-level directory of this distribution + License: GNU Affero General Public License version 3, or any later version + See top-level LICENSE file for more information +%> + + + + jslicense-labels1 + + + +

Web Labels

+ + + + + + + + + + <% for (let jsasset of Object.keys(jslicenses_data).sort((a, b) => { + let va = a.split('/').slice(-1)[0]; + let vb = b.split('/').slice(-1)[0]; + if (va < vb) { + return -1 + } else if (va > vb) { + return 1; + } + return 0; + })) { + let bundled_js_srcs = jslicenses_data[jsasset]; %> + + + + + + <% } %> + +
ScriptLicensesSources
+ <%= jsasset.split('/').slice(-1)[0] %> + + <% for (let i = 0; i < bundled_js_srcs.length ; ++i) { + let js_src = bundled_js_srcs[i]; + for (let j = 0; j < js_src.licenses.length; ++j) { + let js_license = js_src.licenses[j]; %> + <%= js_license.name %> + <% if (js_license.copy_url) { %> + (view) + <% } %> + <% if (j != js_src.licenses.length - 1) {%> +
+ <% } %> + <% } %> + <% if (i != bundled_js_srcs.length - 1) {%> +
+
+ <% } %> + <% } %> +
+ <% for (let i = 0; i < bundled_js_srcs.length ; ++i) { + let js_src = bundled_js_srcs[i]; %> + <%= js_src.id %> + <% for (let j = 0 ; j < js_src.licenses.length - 1; ++j) { %> +
+ <% }%> + <% if (i != bundled_js_srcs.length - 1) {%> +
+
+ <% } %> + <% } %> +
+ + \ No newline at end of file diff --git a/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/plugin-options-schema.json b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/plugin-options-schema.json new file mode 100644 --- /dev/null +++ b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/plugin-options-schema.json @@ -0,0 +1,75 @@ +{ + "type": "object", + "additionalProperties": false, + "properties": { + "outputType": { + "description": "The type of output jslicenses file to generate", + "type": "string", + "enum": ["html", "json"] + }, + "outputDir": { + "description": "Specify the path relative to the webpack output folder of the directory in which weblabels related files will be emitted", + "type": "string" + }, + "exclude": { + "description": "Specify a list of module prefixes to exclude from processing", + "type": "array", + "items": { + "type": "string" + } + }, + "srcReplace": { + "description": "Allow to replace js source files to copy in the generated output", + "type": "object", + "additionalProperties": { "type": "string" } + }, + "licenseOverride": { + "description": "Allow to override the SPDX license expression for given source files", + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "required": ["spdxLicenseExpression", "licenseFilePath"], + "properties": { + "spdxLicenseExpression": { + "description": "A SPDX license expression", + "type": "string" + }, + "licenseFilePath": { + "description": "The path to the corresponding license file relative to the webpack project root", + "type": "string" + } + } + } + }, + "additionalScripts": { + "description": "Allow to declare additional scripts not processed by webpack.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id", "path", "spdxLicenseExpression", "licenseFilePath"], + "properties": { + "id": { + "description": "A js source file identifier as it will be displayed in the Weblabels page", + "type": "string" + }, + "path": { + "description": "The path to the js source file relative to the webpack project root" + }, + "spdxLicenseExpression": { + "description": "A SPDX license expression", + "type": "string" + }, + "licenseFilePath": { + "description": "The path to the corresponding license file relative to the webpack project root", + "type": "string" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/spdx-licenses-mapping.js b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/spdx-licenses-mapping.js new file mode 100644 --- /dev/null +++ b/swh/web/assets/config/webpack-plugins/generate-weblabels-webpack-plugin/spdx-licenses-mapping.js @@ -0,0 +1,135 @@ +/** + * Copyright (C) 2019 The Software Heritage developers + * See the AUTHORS file at the top-level directory of this distribution + * License: GNU Affero General Public License version 3, or any later version + * See top-level LICENSE file for more information + */ + +module.exports = [ + { + 'name': 'Apache License, Version 2.0', + 'url': 'http://www.apache.org/licenses/LICENSE-2.0', + 'magnet_link': 'magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt', + 'spdx_ids': ['Apache-2.0'] + }, + { + 'name': 'Artistic License 2.0', + 'url': 'http://www.perlfoundation.org/artistic_license_2_0', + 'magnet_link': 'magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt', + 'spdx_ids': ['Artistic-2.0'] + }, + { + 'name': 'Boost Software License', + 'url': 'http://www.boost.org/LICENSE_1_0.txt', + 'magnet_link': 'magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt', + 'spdx_ids': ['BSL-1.0'] + }, + { + 'name': 'BSD 3-Clause License', + 'url': 'http://opensource.org/licenses/BSD-3-Clause', + 'magnet_link': 'magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt', + 'spdx_ids': ['BSD-3-Clause'] + }, + { + 'name': 'CPAL 1.0', + 'url': 'http://opensource.org/licenses/cpal_1.0', + 'magnet_link': 'magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt', + 'spdx_ids': ['CPAL-1.0'] + }, + { + 'name': 'Creative Commons CC0 1.0 Universal', + 'url': 'http://creativecommons.org/publicdomain/zero/1.0/legalcode', + 'magnet_link': 'magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt', + 'spdx_ids': ['CC0-1.0'] + }, + { + 'name': 'Eclipse Public License 1.0', + 'url': 'http://www.eclipse.org/legal/epl-v10.html', + 'magnet_link': 'magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt', + 'spdx_ids': ['EPL-1.0'] + }, + { + 'name': 'Expat License', + 'url': 'http://www.jclark.com/xml/copying.txt', + 'magnet_link': 'magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt', + 'spdx_ids': ['MIT'] + }, + { + 'name': 'FreeBSD License', + 'url': 'http://www.freebsd.org/copyright/freebsd-license.html', + 'magnet_link': 'magnet:?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt', + 'spdx_ids': ['BSD-2-Clause-FreeBSD'] + }, + { + 'name': 'GNU General Public License (GPL) version 2', + 'url': 'http://www.gnu.org/licenses/gpl-2.0.html', + 'magnet_link': 'magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt', + 'spdx_ids': ['GPL-2.0-only', 'GPL-2.0-or-later', 'GPL-2.0+', 'GPL-2.0'] + }, + { + 'name': 'GNU General Public License (GPL) version 3', + 'url': 'http://www.gnu.org/licenses/gpl-3.0.html', + 'magnet_link': 'magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt', + 'spdx_ids': ['GPL-3.0-only', 'GPL-3.0-or-later', 'GPL-3.0+', 'GPL-3.0'] + }, + { + 'name': 'GNU Lesser General Public License, version 2.1', + 'url': 'http://www.gnu.org/licenses/lgpl-2.1.html', + 'magnet_link': 'magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt', + 'spdx_ids': ['LGPL-2.1-only', 'LGPL-2.1-or-later', 'LGPL-2.1+', 'LGPL-2.1'] + }, + { + 'name': 'GNU Lesser General Public License, version 3', + 'url': 'http://www.gnu.org/licenses/lgpl-3.0.html', + 'magnet_link': 'magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt', + 'spdx_ids': ['LGPL-3.0-only', 'LGPL-3.0-or-later', 'LGPL-3.0+', 'LGPL-3.0'] + }, + { + 'name': 'GNU Affero General Public License, version 3', + 'url': 'http://www.gnu.org/licenses/agpl-3.0.html', + 'magnet_link': 'magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt', + 'spdx_ids': ['AGPL-3.0-only', 'AGPL-3.0-or-later', 'AGPL-3.0+', 'AGPL-3.0'] + }, + { + 'name': 'The ISC License', + 'url': 'https://www.isc.org/downloads/software-support-policy/isc-license/', + 'magnet_link': 'magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt', + 'spdx_ids': ['ISC'] + }, + { + 'name': 'Mozilla Public License 2.0', + 'url': 'http://www.mozilla.org/MPL/2.0', + 'magnet_link': 'magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt', + 'spdx_ids': ['MPL-2.0'] + }, + { + 'name': 'Universal Permissive License', + 'url': 'https://oss.oracle.com/licenses/upl/', + 'magnet_link': 'magnet:?xt=urn:btih:478974f4d41c3fa84c4befba25f283527fad107d&dn=upl-1.0.txt', + 'spdx_ids': ['UPL-1.0'] + }, + { + 'name': 'WTFPL', + 'url': 'http://www.wtfpl.net/txt/copying/', + 'magnet_link': 'magnet:?xt=urn:btih:723febf9f6185544f57f0660a41489c7d6b4931b&dn=wtfpl.txt', + 'spdx_ids': ['WTFPL'] + }, + { + 'name': 'Unlicense', + 'url': 'http://unlicense.org/UNLICENSE', + 'magnet_link': 'magnet:?xt=urn:btih:5ac446d35272cc2e4e85e4325b146d0b7ca8f50c&dn=unlicense.txt', + 'spdx_ids': ['Unlicense'] + }, + { + 'name': 'X11 License', + 'url': 'http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3', + 'magnet_link': 'magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt', + 'spdx_ids': ['X11'] + }, + { + 'name': 'XFree86 License', + 'url': 'http://www.xfree86.org/current/LICENSE4.html', + 'magnet_link': 'magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt', + 'spdx_ids': ['XFree86-1.1'] + } +]; diff --git a/swh/web/assets/config/webpack.config.development.js b/swh/web/assets/config/webpack.config.development.js --- a/swh/web/assets/config/webpack.config.development.js +++ b/swh/web/assets/config/webpack.config.development.js @@ -17,6 +17,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const RemoveSourceMapUrlPlugin = require('./webpack-plugins/remove-source-map-url-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); +const GenerateWebLabelsPlugin = require('./webpack-plugins/generate-weblabels-webpack-plugin'); // are we running webpack-dev-server ? const isDevServer = process.argv.find(v => v.includes('webpack-dev-server')); @@ -304,7 +305,8 @@ // webpack plugins plugins: [ // cleanup previously generated assets - new CleanWebpackPlugin(['static/css', 'static/js', 'static/fonts', 'static/*.*'], { + new CleanWebpackPlugin(['static/css', 'static/js', 'static/fonts', + 'static/jssources', 'static/*.*'], { root: path.resolve(__dirname, '../../') }), // needed in order to use django_webpack_loader @@ -349,7 +351,39 @@ new CopyWebpackPlugin([{ from: path.resolve(nodeModules, 'pdfjs-dist/build/pdf.worker.min.js'), to: path.resolve(__dirname, '../../static/js/') - }]) + }]), + new GenerateWebLabelsPlugin({ + outputType: 'json', + exclude: ['mini-css-extract-plugin', + 'bootstrap-loader'], + srcReplace: { + './node_modules/pdfjs-dist/build/pdf.min.js': + './node_modules/pdfjs-dist/build/pdf.js', + './node_modules/admin-lte/dist/js/adminlte.min.js': + './node_modules/admin-lte/dist/js/adminlte.js' + }, + licenseOverride: { + './swh/web/assets/src/thirdparty/highlightjs-line-numbers/highlightjs-line-numbers.js': { + 'spdxLicenseExpression': 'MIT', + 'licenseFilePath': './swh/web/assets/src/thirdparty/highlightjs-line-numbers/LICENSE' + }, + './swh/web/assets/src/thirdparty/jquery.tabSlideOut/jquery.tabSlideOut.js': { + 'spdxLicenseExpression': 'GPL-3.0', + 'licenseFilePath': './swh/web/assets/src/thirdparty/jquery.tabSlideOut/LICENSE' + } + }, + additionalScripts: { + 'js/pdf.worker.min.js': [ + { + 'id': 'pdfjs-dist/build/pdf.worker.js', + 'path': './node_modules/pdfjs-dist/build/pdf.worker.js', + 'spdxLicenseExpression': 'Apache-2.0', + 'licenseFilePath': './node_modules/pdfjs-dist/LICENSE' + + } + ] + } + }) ], // webpack optimizations optimization: { diff --git a/swh/web/assets/config/webpack.config.production.js b/swh/web/assets/config/webpack.config.production.js --- a/swh/web/assets/config/webpack.config.production.js +++ b/swh/web/assets/config/webpack.config.production.js @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018 The Software Heritage developers + * Copyright (C) 2018-2019 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information @@ -38,5 +38,8 @@ }) ]; +// prevent modules concatenation for generating weblabels +webpackProdConfig.optimization.concatenateModules = false; + // webpack production configuration module.exports = webpackProdConfig; diff --git a/swh/web/common/swh_templatetags.py b/swh/web/common/swh_templatetags.py --- a/swh/web/common/swh_templatetags.py +++ b/swh/web/common/swh_templatetags.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2018 The Software Heritage developers +# Copyright (C) 2017-2019 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -166,3 +166,17 @@ If the origin type is savable or not """ return origin_type in get_savable_origin_types() + + +@register.filter +def split(value, arg): + """Django template filter to split a string. + + Args: + value (str): the string to split + arg (str): the split separator + + Returns: + list: the splitted string parts + """ + return value.split(arg) diff --git a/swh/web/templates/coverage.html b/swh/web/templates/coverage.html --- a/swh/web/templates/coverage.html +++ b/swh/web/templates/coverage.html @@ -1,5 +1,5 @@ {% comment %} -Copyright (C) 2015-2018 The Software Heritage developers +Copyright (C) 2015-2019 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information @@ -7,6 +7,7 @@ +{% load js_reverse %} {% load static %} {% load render_bundle from webpack_loader %} @@ -18,7 +19,31 @@ Software Heritage archive coverage {% render_bundle 'vendors' %} {% render_bundle 'webapp' %} - + + @@ -41,6 +66,7 @@ + JavaScript license information {% if count_origins %} + + + {% block header %}{% endblock %} @@ -30,6 +56,7 @@ + @@ -170,9 +197,10 @@ forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: - Archive access - - API, - Contact. + Archive access, + API- + Contact- + JavaScript license information
diff --git a/swh/web/urls.py b/swh/web/urls.py --- a/swh/web/urls.py +++ b/swh/web/urls.py @@ -1,12 +1,15 @@ -# Copyright (C) 2017-2018 The Software Heritage developers +# Copyright (C) 2017-2019 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information +import json + from django.conf import settings from django.conf.urls import ( url, include, handler400, handler403, handler404, handler500 ) +from django.contrib.staticfiles import finders from django.contrib.staticfiles.views import serve from django.shortcuts import render from django.views.generic.base import RedirectView @@ -30,6 +33,15 @@ return render(request, "homepage.html") +def jslicenses(request): + jslicenses_file = finders.find('jssources/jslicenses.json') + jslicenses_data = json.load(open(jslicenses_file)) + jslicenses_data = sorted(jslicenses_data.items(), + key=lambda item: item[0].split('/')[-1]) + return render(request, "jslicenses.html", + {'jslicenses_data': jslicenses_data}) + + urlpatterns = [ url(r'^admin/', include('swh.web.admin.urls')), url(r'^favicon\.ico$', favicon_view), @@ -39,7 +51,8 @@ url(r'^jsreverse/$', urls_js, name='js_reverse'), url(r'^(?Pswh:[0-9]+:[a-z]+:[0-9a-f]+.*)/$', swh_id_browse, name='browse-swh-id'), - url(r'^coverage/$', swh_coverage, name='swh-coverage') + url(r'^coverage/$', swh_coverage, name='swh-coverage'), + url(r'^jslicenses/$', jslicenses, name='jslicenses'), ] diff --git a/yarn.lock b/yarn.lock --- a/yarn.lock +++ b/yarn.lock @@ -9,27 +9,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@>=7.1.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" - integrity sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" - "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.2.2" - "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.2.2" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.10" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.3.3": +"@babel/core@>=7.1.0", "@babel/core@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ== @@ -49,18 +29,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.2.2": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.2.tgz#fff31a7b2f2f3dad23ef8e01be45b0d5c2fc0132" - integrity sha512-f3QCuPppXxtZOEm5GWPra/uYUjmNQlu9pbAD8D/9jze4pTY83rTtB1igTBSwvkeNlC5gR24zFFkz+2WHLFQhqQ== - dependencies: - "@babel/types" "^7.3.2" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.3.3": +"@babel/generator@^7.2.2", "@babel/generator@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A== @@ -244,12 +213,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.2.tgz#95cdeddfc3992a6ca2a1315191c1679ca32c55cd" - integrity sha512-QzNUC2RO1gadg+fs21fi0Uu0OuGNzRKEmgCxoLNzbCdoprLwjfmZwzUrpUNfJPaVRwBpDY47A17yYEGWyRelnQ== - -"@babel/parser@^7.3.3": +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg== @@ -363,9 +327,9 @@ lodash "^4.17.10" "@babel/plugin-transform-classes@^7.2.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz#6c90542f210ee975aa2aa8c8b5af7fa73a126953" - integrity sha512-gEZvgTy1VtcDOaQty1l10T3jQmJKlNVxLDCs+3rCVPr6nMkODLELxViq5X9l+rfxbie3XrfrMCYYY6eX3aOcOQ== + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.3.tgz#a0532d6889c534d095e8f604e9257f91386c4b51" + integrity sha512-n0CLbsg7KOXsMF4tSTLCApNMoXk0wOPb0DYfsOO1e7SfIb9gOyfbpKI2MZ+AXfqvlfzq2qsflJ1nEns48Caf2w== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" @@ -492,9 +456,9 @@ "@babel/helper-replace-supers" "^7.1.0" "@babel/plugin-transform-parameters@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.2.0.tgz#0d5ad15dc805e2ea866df4dd6682bfe76d1408c2" - integrity sha512-kB9+hhUidIgUoBQ0MsxMewhzr8i60nMa2KgeJKQWYrqQpqcBYtnpR+JgkadZVZoaEZ/eKu9mclFaVwhRpLNSzA== + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz#3a873e07114e1a5bee17d04815662c8317f10e30" + integrity sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw== dependencies: "@babel/helper-call-delegate" "^7.1.0" "@babel/helper-get-function-arity" "^7.0.0" @@ -652,16 +616,7 @@ globals "^11.1.0" lodash "^4.17.10" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.2": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.2.tgz#424f5be4be633fff33fb83ab8d67e4a8290f5a2f" - integrity sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" integrity sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ== @@ -694,9 +649,9 @@ integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== "@types/node@*": - version "11.9.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.3.tgz#14adbb5ab8cd563f549fbae8dbe92e0b7d6e76cc" - integrity sha512-DMiqG51GwES/c4ScBY0u5bDlH44+oY8AeYHjY1SGCWidD7h08o1dfHue/TGK7REmif2KiJzaUskO+Q0eaeZ2fQ== + version "11.9.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.5.tgz#011eece9d3f839a806b63973e228f85967b79ed3" + integrity sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q== "@types/node@^10.11.7": version "10.12.27" @@ -714,9 +669,9 @@ integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== "@types/unist@*", "@types/unist@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.2.tgz#5dc0a7f76809b7518c0df58689cd16a19bd751c6" - integrity sha512-iHI60IbyfQilNubmxsq4zqSjdynlmc2Q/QvH9kjzg9+CCYVVzq1O6tc7VBzSygIwnmOt07w80IG6HDQvjv3Liw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" + integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== "@types/vfile-message@*": version "1.0.1" @@ -973,9 +928,9 @@ integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== ajv@^6.1.0, ajv@^6.5.5, ajv@^6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" - integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA== + version "6.9.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.2.tgz#4927adb83e7f48e5a32b45729744c71ec39c9c7b" + integrity sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -1229,19 +1184,7 @@ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^9.0.0: - version "9.4.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.7.tgz#f997994f9a810eae47b38fa6d8a119772051c4ff" - integrity sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA== - dependencies: - browserslist "^4.4.1" - caniuse-lite "^1.0.30000932" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.14" - postcss-value-parser "^3.3.1" - -autoprefixer@^9.4.9: +autoprefixer@^9.0.0, autoprefixer@^9.4.9: version "9.4.9" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.9.tgz#0d3eb86bc1d1228551abcf55220d6fd246b6cb31" integrity sha512-OyUl7KvbGBoFQbGQu51hMywz1aaVeud/6uX8r1R1DNcqFvqGUUy6+BDHnAZE8s5t5JyEObaSw+O1DpAdjAmLuw== @@ -1425,12 +1368,7 @@ jquery ">=1.8.2" open-iconic ">=1.1.1" -bootstrap@>=4.0.0, bootstrap@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.0.tgz#2559ccb8d45426ac6c54db23eb3d1c9f4257fa22" - integrity sha512-M0vqY0Z6UDweV2nLFl5dXcb+GIo53EBCGMMVxCGH5vJxl/jsr+HkULBMd4kn9rdpdBZwd3BduCgMOYOwJybo4Q== - -bootstrap@^4.3.1: +bootstrap@>=4.0.0, bootstrap@^4.1.0, bootstrap@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac" integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag== @@ -1536,16 +1474,7 @@ dependencies: pako "~1.0.5" -browserslist@^4.0.0, browserslist@^4.1.1, browserslist@^4.3.4, browserslist@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" - integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A== - dependencies: - caniuse-lite "^1.0.30000929" - electron-to-chromium "^1.3.103" - node-releases "^1.1.3" - -browserslist@^4.4.2: +browserslist@^4.0.0, browserslist@^4.1.1, browserslist@^4.3.4, browserslist@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2" integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg== @@ -1715,12 +1644,7 @@ lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000932: - version "1.0.30000936" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000936.tgz#5d33b118763988bf721b9b8ad436d0400e4a116b" - integrity sha512-orX4IdpbFhdNO7bTBhSbahp1EBpqzBc+qrvTRVUFfZgA4zta7TdM6PN5ZxkEUgDnz36m+PfWGcdX7AVfFWItJw== - -caniuse-lite@^1.0.30000939: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000939: version "1.0.30000939" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz#b9ab7ac9e861bf78840b80c5dfbc471a5cd7e679" integrity sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg== @@ -1818,9 +1742,9 @@ color-convert "^0.5.3" chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.1.tgz#adc39ad55a2adf26548bd2afa048f611091f9184" - integrity sha512-gfw3p2oQV2wEt+8VuMlNsPjCxDxvvgnm/kz+uATu805mWVF8IJN7uz9DN7iBz+RMJISmiVbCOBFs9qBGMjtPfQ== + version "2.1.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058" + integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg== dependencies: anymatch "^2.0.0" async-each "^1.0.1" @@ -1897,16 +1821,6 @@ dependencies: restore-cursor "^2.0.0" -cli-table3@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" - integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== - dependencies: - object-assign "^4.1.0" - string-width "^2.1.1" - optionalDependencies: - colors "^1.1.2" - cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -1970,7 +1884,7 @@ resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= -coa@~2.0.1: +coa@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== @@ -2035,16 +1949,6 @@ color-convert "^1.9.1" color-string "^1.5.2" -colors@^1.1.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" - integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== - -colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" @@ -2092,11 +1996,11 @@ arity-n "^1.0.4" compressible@~2.0.14: - version "2.0.15" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" - integrity sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw== + version "2.0.16" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.16.tgz#a49bf9858f3821b64ce1be0296afc7380466a77f" + integrity sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA== dependencies: - mime-db ">= 1.36.0 < 2" + mime-db ">= 1.38.0 < 2" compression@^1.5.2: version "1.7.3" @@ -2239,9 +2143,9 @@ webpack-log "^2.0.0" core-js@^2.5.7: - version "2.6.4" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.4.tgz#b8897c062c4d769dd30a0ac5c73976c47f92ea0d" - integrity sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A== + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -2259,13 +2163,14 @@ require-from-string "^2.0.1" cosmiconfig@^5.0.0: - version "5.0.7" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.7.tgz#39826b292ee0d78eda137dfa3173bd1c21a43b04" - integrity sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA== + version "5.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.1.0.tgz#6c5c35e97f37f985061cdf653f114784231185cf" + integrity sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q== dependencies: import-fresh "^2.0.0" is-directory "^0.3.1" js-yaml "^3.9.0" + lodash.get "^4.4.2" parse-json "^4.0.0" create-ecdh@^4.0.0: @@ -2392,7 +2297,7 @@ postcss-value-parser "^3.3.0" schema-utils "^1.0.0" -css-select-base-adapter@~0.1.0: +css-select-base-adapter@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== @@ -2443,9 +2348,9 @@ integrity sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w= css-what@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.2.tgz#c0876d9d0480927d7d4920dcd72af3595649554d" - integrity sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ== + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== css@^2.0.0: version "2.2.4" @@ -2533,16 +2438,16 @@ integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== cssnano@^4.1.0: - version "4.1.9" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.9.tgz#f2ac0f5a8b9396fcb11d25fb3aab1e86303fcbd2" - integrity sha512-osEbYy4kzaNY3nkd92Uf3hy5Jqb5Aztuv+Ze3Z6DjRhyntZDlb3YljiYDdJ05k167U86CZpSR+rbuJYN7N3oBQ== + version "4.1.10" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== dependencies: cosmiconfig "^5.0.0" cssnano-preset-default "^4.0.7" is-resolvable "^1.0.0" postcss "^7.0.0" -csso@^3.5.0: +csso@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg== @@ -2867,14 +2772,7 @@ dependencies: ms "2.0.0" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.1.0, debug@^3.2.5: +debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -3087,28 +2985,23 @@ esutils "^2.0.2" dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - integrity sha1-BzxpdUbOB4DOI75KKOKT5AvDDII= + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" + domelementtype "^1.3.0" + entities "^1.1.1" domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1, domelementtype@^1.3.0: +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs= - domhandler@2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" @@ -3186,7 +3079,12 @@ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.113: +ejs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ== + +electron-to-chromium@^1.3.113: version "1.3.113" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9" integrity sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g== @@ -3240,7 +3138,7 @@ resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY= -entities@^1.1.1, entities@~1.1.1: +entities@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== @@ -3281,9 +3179,9 @@ is-symbol "^1.0.2" es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.47" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.47.tgz#d24232e1380daad5449a817be19bde9729024a11" - integrity sha512-/1TItLfj+TTfWoeRcDn/0FbGV6SNo4R+On2GGVucPU/j3BWnXE2Co8h8CTo4Tu34gFJtnmwS9xiScKs4EjZhdw== + version "0.10.48" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.48.tgz#9a0b31eeded39e64453bcedf6f9d50bbbfb43850" + integrity sha512-CdRvPlX/24Mj5L4NVxTs4804sxiS2CjVprgCmrgoDkdmjdY4D+ySHa7K3jJf8R40dFg0tIm3z/dk326LrnuSGw== dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -3900,11 +3798,11 @@ readable-stream "^2.3.6" follow-redirects@^1.0.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.6.1.tgz#514973c44b5757368bad8bddfe52f81f015c94cb" - integrity sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ== + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== dependencies: - debug "=3.1.0" + debug "^3.2.6" font-awesome@^4.7.0: version "4.7.0" @@ -4477,9 +4375,9 @@ integrity sha1-PTIkYrrfB3Fup+uFuviAec3c5QU= homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== dependencies: parse-passwd "^1.0.0" @@ -4535,16 +4433,16 @@ readable-stream "1.1" htmlparser2@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.0.tgz#5f5e422dcf6119c0d983ed36260ce9ded0bee464" - integrity sha512-J1nEUGv+MkXS0weHNWVKJJ+UrLfePxRWpN3C9bEi9fLxL2+ggW94DQvgYVXsaT30PGwYRIZKNZXuyMhp3Di4bQ== + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== dependencies: - domelementtype "^1.3.0" + domelementtype "^1.3.1" domhandler "^2.3.0" domutils "^1.5.1" entities "^1.1.1" inherits "^2.0.1" - readable-stream "^3.0.6" + readable-stream "^3.1.1" http-deceiver@^1.2.7: version "1.2.7" @@ -5654,6 +5552,11 @@ resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + lodash.max@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a" @@ -5935,22 +5838,17 @@ bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.36.0 < 2": +"mime-db@>= 1.38.0 < 2", 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.37.0: - version "1.37.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" - integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== - mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: - version "2.1.21" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" - integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + version "2.1.22" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" + integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== dependencies: - mime-db "~1.37.0" + mime-db "~1.38.0" mime-types@~1.0.1: version "1.0.2" @@ -6292,13 +6190,6 @@ semver "^5.3.0" tar "^4" -node-releases@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.7.tgz#b09a10394d0ed8f7778f72bb861dde68b146303b" - integrity sha512-bKdrwaqJUPHqlCzDD7so/R+Nk0jGv9a11ZhLrD9f6i947qGLrGAhU3OxRENa19QQmwzGy/g6zCDEuLGDO8HPvA== - dependencies: - semver "^5.3.0" - node-releases@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.8.tgz#32a63fff63c5e51b7e0f540ac95947d220fc6862" @@ -6417,9 +6308,9 @@ integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== npm-packlist@^1.1.6: - version "1.3.0" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.3.0.tgz#7f01e8e44408341379ca98cfd756e7b29bd2626c" - integrity sha512-qPBc6CnxEzpOcc4bjoIBJbYdy0D/LFFPUdxvfwor4/w3vxeE0h6TiOVurCEPpQ6trjN77u/ShyfeJGsbAfB3dA== + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" @@ -6529,7 +6420,7 @@ dependencies: isobject "^3.0.1" -object.values@^1.0.4: +object.values@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== @@ -6559,9 +6450,9 @@ ee-first "1.1.1" on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -6766,9 +6657,9 @@ callsites "^3.0.0" parse-asn1@^5.0.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.3.tgz#1600c6cc0727365d68b97f3aa78939e735a75204" - integrity sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg== + version "5.1.4" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" + integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -6778,9 +6669,9 @@ safe-buffer "^5.1.1" parse-entities@^1.0.2, parse-entities@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.0.tgz#9deac087661b2e36814153cb78d7e54a4c5fd6f4" - integrity sha512-XXtDdOPLSB0sHecbEapQi6/58U/ODj/KWfIXmmMCJF/eRn8laX6LZbOyioMoETOOJoWRW8/qTSl5VQkUIfKM5g== + version "1.2.1" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.1.tgz#2c761ced065ba7dc68148580b5a225e4918cdd69" + integrity sha512-NBWYLQm1KSoDKk7GAHyioLTvCZ5QjdH/ASBBQTD3iLiAWJXS5bg1jEWI8nIJ+vgVvsceBVBcDGRWSo0KVQBvvg== dependencies: character-entities "^1.0.0" character-entities-legacy "^1.0.0" @@ -7576,9 +7467,9 @@ integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" - integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" @@ -7689,7 +7580,7 @@ isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^3.0.6: +readable-stream@^3.0.6, readable-stream@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== @@ -7751,9 +7642,9 @@ integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== regenerator-transform@^0.13.3: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" - integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA== + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" + integrity sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A== dependencies: private "^0.1.6" @@ -7771,13 +7662,9 @@ integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== regexp-tree@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.1.tgz#27b455f9b138ca2e84c090e9aff1ffe2a04d97fa" - integrity sha512-HwRjOquc9QOwKTgbxvZTcddS5mlNlwePMQ3NFL8broajMLD5CXDAqas8Y5yxJH5QtZp5iRor3YCILd5pz71Cgw== - dependencies: - cli-table3 "^0.5.0" - colors "^1.1.2" - yargs "^12.0.5" + version "0.1.5" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.5.tgz#7cd71fca17198d04b4176efd79713f2998009397" + integrity sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ== regexpp@^2.0.1: version "2.0.1" @@ -8624,7 +8511,7 @@ dependencies: figgy-pudding "^3.5.1" -stable@~0.1.6: +stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== @@ -8839,9 +8726,9 @@ integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= stylehacks@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.2.tgz#d22eb2767598b1a704341290b42aeafb7945ce38" - integrity sha512-AZwvn2b3aNKK1yp+VgNPOuC2jIJOvh9PAiCq2gjDBW1WkQxQUksR1RugOJRIOhMYTGHZeoMcMQKp3/qaS3evNg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== dependencies: browserslist "^4.0.0" postcss "^7.0.0" @@ -8944,22 +8831,22 @@ integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= svgo@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.1.1.tgz#12384b03335bcecd85cfa5f4e3375fed671cb985" - integrity sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g== + version "1.2.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.2.0.tgz#305a8fc0f4f9710828c65039bb93d5793225ffc3" + integrity sha512-xBfxJxfk4UeVN8asec9jNxHiv3UAMv/ujwBWGYvQhhMb2u3YTGKkiybPcLFDLq7GLLWE9wa73e0/m8L5nTzQbw== dependencies: - coa "~2.0.1" - colors "~1.1.2" + chalk "^2.4.1" + coa "^2.0.2" css-select "^2.0.0" - css-select-base-adapter "~0.1.0" + css-select-base-adapter "^0.1.1" css-tree "1.0.0-alpha.28" css-url-regex "^1.1.0" - csso "^3.5.0" + csso "^3.5.1" js-yaml "^3.12.0" mkdirp "~0.5.1" - object.values "^1.0.4" + object.values "^1.1.0" sax "~1.2.4" - stable "~0.1.6" + stable "^0.1.8" unquote "~1.1.1" util.promisify "~1.0.0" @@ -9012,21 +8899,7 @@ dependencies: execa "^0.7.0" -terser-webpack-plugin@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz#9bff3a891ad614855a7dde0d707f7db5a927e3d9" - integrity sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg== - dependencies: - cacache "^11.0.2" - find-cache-dir "^2.0.0" - schema-utils "^1.0.0" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - terser "^3.16.1" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -terser-webpack-plugin@^1.2.3: +terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8" integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA== @@ -10020,7 +9893,7 @@ y18n "^3.2.1" yargs-parser "^8.1.0" -yargs@^12.0.4, yargs@^12.0.5: +yargs@^12.0.4: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==