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 @@ -68,6 +68,7 @@ "robotstxt-webpack-plugin": "^5.0.0", "sass-loader": "^7.1.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/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,369 @@ +/** + * 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 first draft of a plugin for Webpack >= 4 enabling to generate a WebLabels +// page to be used with the LibreJS Firefox plugin (https://www.gnu.org/software/librejs/). +// The purpose of the WebLabels page is to prevent the loading of the generated +// assets being blocked by the LibreJS Firefox plugin in client browsers. +// To do so, the 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: +// +// - it copies all non-minified source files bundles into the generated JavaScript +// assets into a directory located into the webpack output folder. +// +// - it generates a weblabels.json file into a directory located into the +// webpack output folder. This JSON file should be used with an HTML template +// engine to generate the WebLabels page and it has the following structure: +// +// { +// "": [{ +// "id": "", +// "path": "" +// "license": { +// "name": "", +// "url": "", +// "copy_url": "", +// }, +// "static_url": "" +// }, { +// ... +// }], +// "": [ +// ... +// ], +// ... +// } +// +// So for each JavaScript asset generated by Webpack, the JSON file references +// all the source code files bundled in it along with the detected licenses +// and a link to download the non-minified source codes. +// For each referenced source file, its path corresponds to the relative +// path from the webpack project root folder, while its identifier corresponds +// to the path without the './' or './node_modules/' prefix. + +// The following options can be provided to the plugin: +// +// - outputDir: Specify the directory inside the webpack output folder in which +// the weblabels JSON file and the js sources will be emitted. +// The default value is 'jssources'. +// +// - exclude: An array of module name prefixes to exclude from the generated output. +// If the prefix does not start with './', it is considered as a node module. +// +// - srcReplace: 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: An object mapping source files to their corresponding SPDX licenses. +// 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 must have the following structure: +// +// { +// "": { +// "name": "", +// "path": "" +// }, +// ... +// } +// +// - additionalScripts: An object declaring additional js scripts loaded by your web +// application but not processed by webpack. It must have the +// following structure: +// +// { +// "": [{ +// "id": "", +// "path": "" +// "license": { +// "name": "", +// "path": "" +// } +// }, { +// ... +// }], +// ... +// } + +const fs = require('fs'); +const path = require('path'); +const spdxParse = require('spdx-expression-parse'); +const spdxLicensesMapping = require('./spdx-licenses-mapping'); + +class GenerateWebLabelsPlugin { + + constructor(opts) { + this.options = opts || {}; + this.weblabelsDirName = this.options['outputDir'] || 'jssources'; + // 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(); + // 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('GenerateWebLabelsPlugin', 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; + + 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), + 'path': 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 licenseFilePath; + if (this.options['licenseOverride'] && this.options['licenseOverride'].hasOwnProperty(srcFilePath)) { + let licenseSpdxId = this.options['licenseOverride'][srcFilePath]['name']; + licenseFilePath = this.options['licenseOverride'][srcFilePath]['path']; + srcFileData['license'] = this.spdxToWebLabelsLicense(licenseSpdxId); + srcFileData['license']['copy_url'] = this.copyLicenseFile(licenseFilePath); + } else { + srcFileData['license'] = this.extractLicenseInformation(packageJson); + let licenseDir = path.join(...packageJsonPath.split('/').slice(0, -1)); + licenseFilePath = this.findLicenseFile(licenseDir); + } + + // copy original license file and get its static url + srcFileData['license']['copy_url'] = this.copyLicenseFile(licenseFilePath); + + // generate static url for downloading non-minified source code + srcFileData['static_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 licenceFilePath = scriptSrc['license']['path']; + scriptSrc['license'] = this.spdxToWebLabelsLicense(scriptSrc['license']['name']); + scriptSrc['license']['copy_url'] = this.copyLicenseFile(licenceFilePath); + scriptSrc['static_url'] = stats.publicPath + path.join(this.weblabelsDirName, scriptSrc['id']); + this.chunkJsAssetToSrcFiles[script].push(scriptSrc); + this.copyFileToOutputPath(scriptSrc['path']); + } + } + } + + // generate the weblabels.json file + let weblabelsData = JSON.stringify(this.chunkJsAssetToSrcFiles); + let weblabelsJsonFile = path.join(this.weblabelsOutputDir, 'weblabels.json'); + fs.writeFileSync(weblabelsJsonFile, weblabelsData); + }); + } + + 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 (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]; + } + + 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; + } + } + return undefined; + } + + extractLicenseInformation(packageJson) { + let licenseStr; + if (packageJson.hasOwnProperty('license')) { + licenseStr = packageJson['license']; + } else if (packageJson.hasOwnProperty('licenses')) { + let licenses = packageJson['licenses']; + if (Array.isArray(licenses)) { + let l = []; + licenses.forEach(license => { + l.push(license['type']); + }); + licenseStr = l.join(' OR '); + } else { + licenseStr = licenses['type']; + } + } + let license = spdxParse(licenseStr)['license']; + let licenseData = this.spdxToWebLabelsLicense(license); + if (licenseData) { + return licenseData; + } else { + return {'name': license}; + } + } + + 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/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({ + 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': { + 'name': 'MIT', + 'path': './swh/web/assets/src/thirdparty/highlightjs-line-numbers/LICENSE' + }, + './swh/web/assets/src/thirdparty/jquery.tabSlideOut/jquery.tabSlideOut.js': { + 'name': 'GPL-3.0', + 'path': './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', + 'license': { + 'name': 'Apache-2.0', + 'path': './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 @@ + @@ -172,7 +199,8 @@ Terms of use: Archive access - API, - Contact. + 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,14 @@ return render(request, "homepage.html") +def jslicenses(request): + jslicenses_data = json.load(open(finders.find('jssources/weblabels.json'))) + 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 +50,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.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.4.tgz#ceb0048a546db453f6248f2d1d95e937a6f00a14" + integrity sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA== "@types/q@^1.5.1": version "1.5.1" @@ -704,9 +659,9 @@ integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA== "@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" @@ -1344,12 +1299,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== @@ -1640,9 +1590,9 @@ 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== + version "1.0.30000938" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000938.tgz#b64bf1427438df40183fce910fe24e34feda7a3f" + integrity sha512-ekW8NQ3/FvokviDxhdKLZZAx7PptXNwxKgXtnR5y+PR3hckwuP3yJ1Ir+4/c97dsHNqtAyfKUGdw8P4EYzBNgw== capture-stack-trace@^1.0.0: version "1.0.1" @@ -1737,9 +1687,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" @@ -1809,16 +1759,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" @@ -1939,11 +1879,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" @@ -1984,11 +1919,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" @@ -2121,9 +2056,9 @@ serialize-javascript "^1.4.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" @@ -2141,13 +2076,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: @@ -2318,9 +2254,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" @@ -2401,9 +2337,9 @@ 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" @@ -2718,14 +2654,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== @@ -2928,28 +2857,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.0: version "2.4.2" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" @@ -3049,7 +2973,7 @@ memory-fs "^0.4.0" tapable "^1.0.0" -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== @@ -3692,11 +3616,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" @@ -4215,16 +4139,16 @@ integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= 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" @@ -5230,6 +5154,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" @@ -5506,22 +5435,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@1.4.1: version "1.4.1" @@ -6281,9 +6205,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" @@ -7174,7 +7098,7 @@ string_decoder "~1.1.1" util-deprecate "~1.0.1" -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== @@ -7246,13 +7170,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" @@ -8238,9 +8158,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" @@ -9299,7 +9219,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==