From f943279307edc5e9ab0c4be9bc2652d558f83ab1 Mon Sep 17 00:00:00 2001 From: Nikita Prabhakar <53308018+nikitaprabhakar@users.noreply.github.com> Date: Thu, 9 Apr 2020 20:40:34 -0500 Subject: [PATCH] breaking: represent the feature file tree in sidebar buttons (#41) BEAKING CHANGE: breaks method param order --- .travis/regenerateDocsReport.js | 29 +- README.md | 8 +- features/generate_report.feature | 35 +- features/support/generationSteps.js | 54 +- features/support/usageSteps.js | 84 +- features/support/world.js | 13 +- features/use_report.feature | 35 +- package-lock.json | 1303 ++++++++++++++----- package.json | 16 +- src/Generator.js | 277 ++-- src/templates/doc_template.html | 17 +- src/templates/feature_template.html | 6 +- src/templates/scripts.js | 73 +- src/templates/sidenav_buttons_template.html | 25 + src/templates/style.css | 257 ++-- 15 files changed, 1526 insertions(+), 706 deletions(-) create mode 100644 src/templates/sidenav_buttons_template.html diff --git a/.travis/regenerateDocsReport.js b/.travis/regenerateDocsReport.js index 9274a64..80a5801 100644 --- a/.travis/regenerateDocsReport.js +++ b/.travis/regenerateDocsReport.js @@ -1,34 +1,9 @@ #!/usr/bin/env node const fs = require('fs'); const path = require('path'); -const { exec } = require('child_process'); const Generator = require('../src/Generator'); const FILE_ENCODING = 'utf-8'; -const getFeatureFiles = (directoryName) => { - if (directoryName.endsWith('node_modules')) { - return []; - } - - // Recurse on directories: - const isDirectory = (source) => fs.lstatSync(source).isDirectory(); - const getDirectories = (source) => fs - .readdirSync(source) - .map((name) => path.join(source, name)) - .filter(isDirectory); - const subDirectories = getDirectories(directoryName); - const featureFiles = []; - subDirectories.forEach((subDirectory) => featureFiles.push(...getFeatureFiles(subDirectory))); - - // Add feature files from this directory. - const allFiles = fs.readdirSync(directoryName); - const localFeatureFiles = allFiles.filter((item) => item.endsWith('.feature')); - localFeatureFiles.forEach((featureFileName) => featureFiles.push(`${directoryName}/${featureFileName}`)); - return featureFiles; -}; - -const featureFiles = getFeatureFiles(path.resolve(__dirname, '../')); -new Generator().generate(featureFiles, 'cucumber-forge-report-generator').then((result) => { - fs.writeFileSync(path.resolve(__dirname, '../docs/index.html'), result, FILE_ENCODING); -}); +const report = new Generator().generate(path.resolve(__dirname, '../'), 'cucumber-forge-report-generator') +fs.writeFileSync(path.resolve(__dirname, '../docs/index.html'), report, FILE_ENCODING); diff --git a/README.md b/README.md index 9527bce..47ec48a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![Build Status](https://travis-ci.com/cerner/cucumber-forge-report-generator.svg?branch=master)](https://travis-ci.com/cerner/cucumber-forge-report-generator) # _About_ + _Note: this repository contains the library for generating Cucumber reports. [Cucumber Forge Desktop](https://github.com/cerner/cucumber-forge-desktop) is a user-friendly desktop application for creating reports with cucumber-forge-report-generator._ The cucumber-forge-report-generator can be used to create clean HTML reports without having to build the project or run the tests. Of course, no pass/fail information for the scenarios is included in the report since the tests are not executed. @@ -19,12 +20,14 @@ Many other solutions exist for creating reports based on the output of Cucumber # _Usage_ -Sample - Generates a report from two feature files with the scenarios filtered by a tag: +Sample - Generates a report for the feature files in a given directory with the scenarios filtered by a tag: + ```js const Generator = require('cucumber-forge-report-generator'); const generator = new Generator(); -const htmlReportString = generator.generate([filePathString1, filePathString2], 'Project Name', 'TagFilter'); +const htmlReportString = generator.generate(featureDirectoryPath, 'Project Name', 'TagFilter'); ``` + Detailed usage documentation can be found [here](https://engineering.cerner.com/cucumber-forge-report-generator/). # _Availability_ @@ -38,6 +41,7 @@ This project is built on [Travis](https://travis-ci.com/cerner/cucumber-forge-re # _Building_ Development Environment: + * [NPM](https://www.npmjs.com/) - ^6.4.1 * [Node.Js](https://nodejs.org) - ^10.14.1 diff --git a/features/generate_report.feature b/features/generate_report.feature index f3f9ce3..1c7a37a 100644 --- a/features/generate_report.feature +++ b/features/generate_report.feature @@ -4,7 +4,7 @@ Feature: Report Generation to generate HTML reports directly from feature files Background: - Given there is a file named 'dog_care.feature' with the following contents: + Given there is a file named 'dog_care.feature' in the 'feature/dog' directory with the following contents: """ @pet_care @dogs Feature: Dog Care @@ -34,7 +34,7 @@ Feature: Report Generation | backwards | lick my hand | | forwards | growl | """ - And there is a file named 'cat_care.feature' with the following contents: + And there is a file named 'cat_care.feature' in the 'feature/cat' directory with the following contents: """ @pet_care @cats Feature: Cat Care @@ -65,15 +65,16 @@ Feature: Report Generation | backwards | | forwards | """ - And the variable 'dogCarePath' contains the path to 'dog_care.feature' - And the variable 'catCarePath' contains the path to 'cat_care.feature' + And the variable 'dogCarePath' contains the path to the 'feature/dog' directory + And the variable 'catCarePath' contains the path to the 'feature/cat' directory + And the variable 'allFeaturesPath' contains the path to the 'feature' directory Scenario: Generating an HTML report for a feature file Given the current date is {current_date} And the username of the current user is {username} - When a report is generated with the code "new Generator().generate([this.dogCarePath])" + When a report is generated with the code "new Generator().generate(this.dogCarePath)" Then the title on the report will be "Feature documentation - {current_date}" - And the report will inculude CSS styling + And the report will include CSS styling And the report will include a favicon And the report will contain 1 feature And the report will contain 2 scenarios @@ -82,19 +83,21 @@ Feature: Report Generation And the project title on the sidebar will be "Feature documentation" And the header on the sidebar will be "{username} - {current_date}" And the footer on the sidebar will be "Cucumber Forge" + And the sidebar will contain 1 directory button And the sidebar will contain 1 feature button And the sidebar will contain 2 scenario buttons - Scenario: Generating an HTML report for multiple feature files - When a report is generated with the code "new Generator().generate([this.dogCarePath, this.catCarePath])" + Scenario: Generating an HTML report for multiple feature files in different directories + When a report is generated with the code "new Generator().generate(this.allFeaturesPath)" Then the report will contain 2 features And the report will contain 4 scenarios + And the sidebar will contain 2 directory buttons And the sidebar will contain 2 feature buttons And the sidebar will contain 4 scenario buttons Scenario: Generating an HTML report when the project name is provided Given the current date is {current_date} - When a report is generated with the code "new Generator().generate([this.dogCarePath], 'Pet Project')" + When a report is generated with the code "new Generator().generate(this.dogCarePath, 'Pet Project')" Then the title on the report will be "Pet Project - {current_date}" And the project title on the sidebar will be "Pet Project" @@ -102,7 +105,7 @@ Feature: Report Generation The features and scenarios included in a report can be filtered based on their tags. The provided tag can optionally be prefixed with '@'. - When a report is generated with the code "new Generator().generate([this.dogCarePath, this.catCarePath], null, )" + When a report is generated with the code "new Generator().generate(this.allFeaturesPath, null, )" Then the report will contain 2 features And the report will contain 2 scenarios And the report name on the sidebar will be @@ -114,7 +117,13 @@ Feature: Report Generation | 'feeding' | | '@feeding' | - Scenario: Generating a report when no feature files are provided + @exception + Scenario: Generating a report when no path is provided When a report is generated with the code "new Generator().generate()" - Then the report will contain 0 features - And the sidebar will contain 0 feature buttons + Then an error will be thrown with the message "A feature directory path must be provided." + + @exception + Scenario: Generating a report when no feature files are provided + Given the variable 'noFeaturesPath' contains the path to a directory with no feature files + When a report is generated with the code "new Generator().generate(this.noFeaturesPath)" + Then an error will be thrown with the message "No feature files were found in the given directory." diff --git a/features/support/generationSteps.js b/features/support/generationSteps.js index eae5bc7..51d9a46 100644 --- a/features/support/generationSteps.js +++ b/features/support/generationSteps.js @@ -12,14 +12,35 @@ const FILE_ENCODING = 'utf-8'; // eslint-disable-next-line no-unused-vars const Generator = require('../../src/Generator'); -Given('there is a file named {string} with the following contents:', function (fileName, contents) { - const filePath = path.resolve(__dirname, fileName); +Given('there is a file named {string} in the {string} directory with the following contents:', function (fileName, fileDirectory, contents) { + const dirPaths = fileDirectory.split('/'); + let dirPath = path.resolve(__dirname, dirPaths[0]); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + this.featureDirs.push(dirPath); + } + if (dirPaths.length > 1) { + dirPath = path.resolve(dirPath, dirPaths[1]); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + this.featureDirs.push(dirPath); + } + } + const filePath = path.resolve(dirPath, fileName); this.featureFiles.push(filePath); fs.writeFileSync(filePath, contents, FILE_ENCODING); }); -Given('the variable {string} contains the path to {string}', function (variableName, fileName) { - this[variableName] = path.resolve(__dirname, fileName); +Given('the variable {string} contains the path to the {string} directory', function (variableName, fileName) { + this[variableName] = path.resolve(__dirname, ...fileName.split('/')); +}); + +Given('the variable {string} contains the path to a directory with no feature files', function (variableName) { + const dirPath = path.resolve(__dirname, 'noFeatures'); + fs.mkdirSync(dirPath); + this.featureDirs.push(dirPath); + + this[variableName] = dirPath; }); Given(/^the current date is \{current_date\}$/, function () { @@ -31,9 +52,19 @@ Given(/^the username of the current user is \{username\}$/, function () { }); When('a report is generated with the code {string}', function (generationFunction) { - // eslint-disable-next-line no-eval - return eval(generationFunction) - .then(output => this.setOutput(output)); + try { + // eslint-disable-next-line no-eval + this.setOutput(eval(generationFunction)); + } catch (error) { + if (!this.exceptionScenario) { + throw error; + } + this.setOutput(error); + } +}); + +Then('an error will be thrown with the message {string}', function (errMsg) { + expect(this.output.message).to.eq(errMsg); }); Then('the title on the report will be {string}', function (reportTitle) { @@ -41,7 +72,7 @@ Then('the title on the report will be {string}', function (reportTitle) { expect(this.outputHTML.title).to.eql(title); }); -Then('the report will inculude CSS styling', function () { +Then('the report will include CSS styling', function () { const styles = this.outputHTML.getElementsByTagName('STYLE'); expect(styles.length).to.eql(1); const style = styles.item(0); @@ -88,10 +119,15 @@ Then('the report will contain {int} scenario(s)', function (scenarioCount) { Then('the report will not contain gherkin comments', function () { const commentPattern = new RegExp('^#.*'); const comments = Array.from(this.outputHTML.getElementsByTagName('*')) - .filter(obj => commentPattern.test(obj.innerHTML)); + .filter((obj) => commentPattern.test(obj.innerHTML)); expect(comments.length).to.eql(0); }); +Then('the sidebar will contain {int} directory button(s)', function (directoryButtonCount) { + const directoryButtons = this.outputHTML.getElementsByClassName('directory-button'); + expect(directoryButtons.length).to.eql(directoryButtonCount); +}); + Then('the sidebar will contain {int} feature button(s)', function (featureButtonCount) { const featureButtons = this.outputHTML.getElementsByClassName('feature-button'); expect(featureButtons.length).to.eql(featureButtonCount); diff --git a/features/support/usageSteps.js b/features/support/usageSteps.js index 449a1c6..f2a22fa 100644 --- a/features/support/usageSteps.js +++ b/features/support/usageSteps.js @@ -6,19 +6,19 @@ const { expect } = require('chai'); const Generator = require('../../src/Generator'); -Given('there is a report for the following feature files:', function (featureFilesTable) { - const getPath = fileName => path.resolve(__dirname, fileName[0]); - const filePaths = featureFilesTable.raw().map(getPath); - return new Generator().generate(filePaths).then(report => this.setOutput(report)); +Given('there is a report for the {string} directory', function (fileDirectory) { + const filePath = path.resolve(__dirname, ...fileDirectory.split('/')); + this.setOutput(new Generator().generate(filePath)); }); -Given('there is a report for the feature file {string}', function (featureFile) { - const filePath = path.resolve(__dirname, featureFile); - return new Generator().generate([filePath]).then(report => this.setOutput(report)); +When(/^the (first|second) directory button is clicked$/, function (directoryIndex) { + const index = directoryIndex === 'first' ? 0 : 1; + this.outputHTML.getElementsByClassName('directory-button')[index].click(); }); -When('the second feature button is clicked', function () { - const featureButton = this.outputHTML.getElementsByClassName('feature-button')[1]; +When(/^the (first|second) feature button is clicked$/, function (featureIndex) { + const index = featureIndex === 'first' ? 0 : 1; + const featureButton = this.outputHTML.getElementsByClassName('feature-button')[index]; const scrolledElement = this.outputHTML.getElementById(featureButton.getAttribute('scroll-to-id')); scrolledElement.scrollIntoView = () => { this.scrolledIntoView = scrolledElement; }; featureButton.click(); @@ -36,7 +36,7 @@ When(/^the (first|second) scenario button is clicked$/, function (scenarioIndex) When(/^the (first|second) scenario is scrolled into view$/, function (scenarioIndex) { const index = scenarioIndex === 'first' ? 0 : 1; const activeFeature = this.outputHTML.getElementsByClassName('feature-wrapper active')[0]; - const scenarioAnchors = Array.from(activeFeature.getElementsByClassName('anchor')).filter(anchor => anchor.hasAttribute('scenario-button')); + const scenarioAnchors = Array.from(activeFeature.getElementsByClassName('anchor')).filter((anchor) => anchor.hasAttribute('scenario-button')); const scenarioAnchor = scenarioAnchors[index]; // To simulate scrolling, set the active class on our desired anchor // and then trigger the scroll event. @@ -73,27 +73,55 @@ Then(/^the (first|second) feature (?:is|will be) displayed$/, function (featureI }); }); +Then(/^the feature button for the (first|second) directory (?:is|will be) expanded in the sidebar/, function (directoryIndex) { + const index = directoryIndex === 'first' ? 0 : 1; + const selectedDirectoryButton = this.outputHTML.getElementsByClassName('directory-button')[index]; + expect(selectedDirectoryButton.classList.contains('active')).to.be.true; + + const featurePanel = selectedDirectoryButton.nextElementSibling; + expect(featurePanel.classList.contains('active')).to.be.true; + + const selectedIcon = selectedDirectoryButton.getElementsByTagName('i')[0]; + expect(selectedIcon.classList.contains('fa-folder-open')).to.be.true; + expect(selectedIcon.classList.contains('fa-folder')).to.be.false; +}); + +Then(/^the feature button for the (first|second) directory (?:is not|will not be) expanded in the sidebar/, function (directoryIndex) { + const index = directoryIndex === 'first' ? 0 : 1; + const selectedDirectoryButton = this.outputHTML.getElementsByClassName('directory-button')[index]; + expect(selectedDirectoryButton.classList.contains('active')).to.be.false; + + const featurePanel = selectedDirectoryButton.nextElementSibling; + expect(featurePanel.classList.contains('active')).to.be.false; + + const selectedIcon = selectedDirectoryButton.getElementsByTagName('i')[0]; + expect(selectedIcon.classList.contains('fa-folder-open')).to.be.false; + expect(selectedIcon.classList.contains('fa-folder')).to.be.true; +}); + Then(/^the scenario buttons for the (first|second) feature (?:are|will be) expanded in the sidebar$/, function (featureIndex) { const index = featureIndex === 'first' ? 0 : 1; - const featureButtons = this.outputHTML.getElementsByClassName('feature-button'); - const selectedFeatureButton = featureButtons[index]; + const selectedFeatureButton = this.outputHTML.getElementsByClassName('feature-button')[index]; expect(selectedFeatureButton.classList.contains('active')).to.be.true; + const scenarioPanel = selectedFeatureButton.nextElementSibling; - expect(scenarioPanel.style.maxHeight).to.not.be.empty; + expect(scenarioPanel.classList.contains('active')).to.be.true; + const selectedIcon = selectedFeatureButton.getElementsByTagName('i')[0]; expect(selectedIcon.classList.contains('fa-angle-down')).to.be.true; expect(selectedIcon.classList.contains('fa-angle-right')).to.be.false; +}); - Array.from(featureButtons).forEach((featureButton) => { - if (selectedFeatureButton !== featureButton) { - expect(featureButton.classList.contains('active')).to.be.false; - const panel = featureButton.nextElementSibling; - expect(panel.style.maxHeight).to.be.empty; - const icon = featureButton.getElementsByTagName('i')[0]; - expect(icon.classList.contains('fa-angle-down')).to.be.false; - expect(icon.classList.contains('fa-angle-right')).to.be.true; - } - }); +Then(/^the scenario buttons for the (first|second) feature (?:are not|will not be) expanded in the sidebar$/, function (featureIndex) { + const index = featureIndex === 'first' ? 0 : 1; + const featureButton = this.outputHTML.getElementsByClassName('feature-button')[index]; + + expect(featureButton.classList.contains('active')).to.be.false; + const panel = featureButton.nextElementSibling; + expect(panel.classList.contains('active')).to.be.false; + const icon = featureButton.getElementsByTagName('i')[0]; + expect(icon.classList.contains('fa-angle-down')).to.be.false; + expect(icon.classList.contains('fa-angle-right')).to.be.true; }); Then(/^the (first|second) scenario button will be highlighted$/, function (scenarioIndex) { @@ -110,14 +138,14 @@ Then(/^the (first|second) scenario button will be highlighted$/, function (scena Then(/^the (first|second) scenario will be scrolled into view$/, function (scenarioIndex) { const index = scenarioIndex === 'first' ? 0 : 1; const activeFeature = this.outputHTML.getElementsByClassName('feature-wrapper active')[0]; - const scenarioAnchors = Array.from(activeFeature.getElementsByClassName('anchor')).filter(anchor => anchor.hasAttribute('scenario-button')); + const scenarioAnchors = Array.from(activeFeature.getElementsByClassName('anchor')).filter((anchor) => anchor.hasAttribute('scenario-button')); expect(this.scrolledIntoView).to.eql(scenarioAnchors[index]); }); Then(/^the settings drawer will be (displayed|hidden)$/, function (visibility) { const settingsDrawer = this.outputHTML.getElementById('settingsDrawer'); const visibilityStatus = settingsDrawer.classList.contains('active'); - if('displayed' === visibility) { + if (visibility === 'displayed') { expect(visibilityStatus).to.be.true; } else { expect(visibilityStatus).to.be.false; @@ -126,13 +154,13 @@ Then(/^the settings drawer will be (displayed|hidden)$/, function (visibility) { Then('the tags displayed for the feature will be {string}', function (expectedTagString) { const activeFeature = this.outputHTML.getElementsByClassName('feature-wrapper active')[0]; - const actualTagString = activeFeature.getElementsByClassName('tags')[0].textContent; + const actualTagString = activeFeature.getElementsByClassName('tags')[0].textContent; expect(actualTagString.trim()).to.eql(expectedTagString); }); Then('the tags displayed for the {word} scenario will be {string}', function (scenarioIndex, expectedTagString) { const activeFeature = this.outputHTML.getElementsByClassName('feature-wrapper active')[0].getElementsByClassName('feature-body')[0]; const index = scenarioIndex === 'first' ? 0 : 1; - const actualTagString = activeFeature.getElementsByClassName('tags')[index].textContent; + const actualTagString = activeFeature.getElementsByClassName('tags')[index].textContent; expect(actualTagString.trim()).to.eql(expectedTagString); -}); \ No newline at end of file +}); diff --git a/features/support/world.js b/features/support/world.js index 37f3e3d..84d34c0 100644 --- a/features/support/world.js +++ b/features/support/world.js @@ -1,15 +1,17 @@ -const { setWorldConstructor, After } = require('cucumber'); +const { setWorldConstructor, After, Before } = require('cucumber'); const { JSDOM } = require('jsdom'); const fs = require('fs'); class CustomWorld { constructor() { this.featureFiles = []; + this.featureDirs = []; this.output = null; this.window = null; this.outputHTML = null; this.tag = null; this.scrolledIntoView = null; + this.exceptionScenario = false; } setOutput(output) { @@ -30,9 +32,14 @@ class CustomWorld { } } +Before({ tags: '@exception' }, function () { + this.exceptionScenario = true; +}); + After(function () { -// Clean up any feature files that got written. - return this.featureFiles.forEach(filePath => fs.unlinkSync(filePath)); + // Clean up any feature files that got written. + this.featureFiles.forEach((filePath) => fs.unlinkSync(filePath)); + this.featureDirs.reverse().forEach((featureDir) => fs.rmdirSync(featureDir)); }); setWorldConstructor(CustomWorld); diff --git a/features/use_report.feature b/features/use_report.feature index 664d51a..727df9f 100644 --- a/features/use_report.feature +++ b/features/use_report.feature @@ -4,7 +4,7 @@ Feature: Report Usage to be able to navigate the report with the built-in functionality Background: - Given there is a file named 'dog_care.feature' with the following contents: + Given there is a file named 'dog_care.feature' in the 'feature/dog' directory with the following contents: """ @pet_care @dogs Feature: Dog Care @@ -34,7 +34,7 @@ Feature: Report Usage | backwards | lick my hand | | forwards | growl | """ - And there is a file named 'cat_care.feature' with the following contents: + And there is a file named 'cat_care.feature' in the 'feature/cat' directory with the following contents: """ @pet_care @cats Feature: Cat Care @@ -66,18 +66,33 @@ Feature: Report Usage | forwards | """ + Scenario: Clicking the directory buttons + Given there is a report for the 'feature' directory + And the feature button for the first directory is expanded in the sidebar + And the feature button for the second directory is not expanded in the sidebar + When the second directory button is clicked + Then the feature button for the second directory will be expanded in the sidebar + And the feature button for the first directory is expanded in the sidebar + When the first directory button is clicked + Then the feature button for the first directory will not be expanded in the sidebar + And the feature button for the second directory is expanded in the sidebar + Scenario: Clicking the feature buttons - Given there is a report for the following feature files: - | dog_care.feature | - | cat_care.feature | + Given there is a report for the 'feature' directory And the first feature is displayed And the scenario buttons for the first feature are expanded in the sidebar + And the scenario buttons for the second feature are not expanded in the sidebar When the second feature button is clicked Then the second feature will be displayed And the scenario buttons for the second feature will be expanded in the sidebar + And the scenario buttons for the first feature are expanded in the sidebar + When the first feature button is clicked + Then the second feature will be displayed + And the scenario buttons for the first feature will not be expanded in the sidebar + And the scenario buttons for the second feature are expanded in the sidebar Scenario: Clicking the scenario buttons - Given there is a report for the feature file 'dog_care.feature' + Given there is a report for the 'feature/dog' directory And the report will contain 2 scenarios When the first scenario button is clicked Then the first scenario button will be highlighted @@ -87,23 +102,23 @@ Feature: Report Usage And the second scenario will be scrolled into view Scenario: Scrolling through the scenarios in a feature - Given there is a report for the feature file 'dog_care.feature' + Given there is a report for the 'feature/dog' directory When the first scenario is scrolled into view Then the first scenario button will be highlighted When the second scenario is scrolled into view Then the second scenario button will be highlighted Scenario: Opening the settings drawer - Given there is a report for the feature file 'dog_care.feature' + Given there is a report for the 'feature/dog' directory When the settings button is clicked Then the settings drawer will be displayed When the settings button is clicked Then the settings drawer will be hidden Scenario: Showing the tags in the report - Given there is a report for the feature file 'dog_care.feature' + Given there is a report for the 'feature/dog' directory And the settings button is clicked When the box is checked to show tags Then the tags displayed for the feature will be '@pet_care @dogs' Then the tags displayed for the first scenario will be '@feeding' - Then the tags displayed for the second scenario will be '@petting' \ No newline at end of file + Then the tags displayed for the second scenario will be '@petting' diff --git a/package-lock.json b/package-lock.json index 81ce1c8..114704c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,10 +94,28 @@ "regenerator-runtime": "^0.13.2" } }, + "@babel/runtime-corejs3": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.2.tgz", + "integrity": "sha512-HHxmgxbIzOfFlZ+tdeRKtaxWOMUoCG5Mu3wKeUmOxjYrwb3AAHgnmtCUbPPK11/raIWLIBK250t8E2BPO0p7jA==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + } + } + }, "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, "acorn": { @@ -107,21 +125,13 @@ "dev": true }, "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", - "dev": true - } + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" } }, "acorn-jsx": { @@ -131,9 +141,9 @@ "dev": true }, "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", "dev": true }, "ajv": { @@ -189,12 +199,6 @@ "commander": "^2.11.0" } }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", @@ -216,9 +220,9 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", - "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -312,12 +316,6 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -331,9 +329,9 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", "dev": true }, "axobject-query": { @@ -383,9 +381,9 @@ } }, "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, "callsites": { @@ -507,9 +505,9 @@ "dev": true }, "confusing-browser-globals": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz", - "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", "dev": true }, "contains-path": { @@ -524,6 +522,12 @@ "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", "dev": true }, + "core-js-pure": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz", + "integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -561,15 +565,15 @@ } }, "cssom": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.1.tgz", - "integrity": "sha512-6Aajq0XmukE7HdXUU6IoSWuH1H6gH9z6qmagsstTiN7cW2FNTsb+J2Chs+ufPgZCsV/yo8oaEudQLrb9dGxSVQ==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, "cssstyle": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.0.0.tgz", - "integrity": "sha512-QXSAu2WBsSRXCPjvI43Y40m6fMevvyRm8JVAuF9ksQz5jha4pWP1wpaK7Yu5oLFc6+XAY+hj8YhefyXcBB53gg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", + "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", "dev": true, "requires": { "cssom": "~0.3.6" @@ -680,14 +684,14 @@ } }, "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" } }, "debug": { @@ -699,6 +703,12 @@ "ms": "^2.1.1" } }, + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", + "dev": true + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -735,6 +745,11 @@ "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true }, + "directory-tree": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-2.2.4.tgz", + "integrity": "sha512-2N43msQptKbi3WMfIs+U09yi6bfyKL+MWyj5VMj8t1F/Tx04bt1cn/EEIU3o1JBltlJk7NQnzOEuTNa/KQvbWA==" + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -745,12 +760,20 @@ } }, "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "requires": { - "webidl-conversions": "^4.0.2" + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } } }, "duration": { @@ -861,12 +884,12 @@ "dev": true }, "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", "dev": true, "requires": { - "esprima": "^3.1.3", + "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", @@ -1000,24 +1023,24 @@ } }, "eslint-config-airbnb-base": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", - "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz", + "integrity": "sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw==", "dev": true, "requires": { - "confusing-browser-globals": "^1.0.7", + "confusing-browser-globals": "^1.0.9", "object.assign": "^4.1.0", - "object.entries": "^1.1.0" + "object.entries": "^1.1.1" } }, "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", "dev": true, "requires": { "debug": "^2.6.9", - "resolve": "^1.5.0" + "resolve": "^1.13.1" }, "dependencies": { "debug": { @@ -1034,13 +1057,22 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } } } }, "eslint-module-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz", - "integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", "dev": true, "requires": { "debug": "^2.6.9", @@ -1064,16 +1096,10 @@ } } }, - "eslint-plugin-eslint-plugin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz", - "integrity": "sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg==", - "dev": true - }, "eslint-plugin-import": { - "version": "2.19.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz", - "integrity": "sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==", + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", + "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", "dev": true, "requires": { "array-includes": "^3.0.3", @@ -1116,9 +1142,9 @@ "dev": true }, "resolve": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", - "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1144,23 +1170,36 @@ } }, "eslint-plugin-react": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz", - "integrity": "sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", "dev": true, "requires": { - "array-includes": "^3.0.3", + "array-includes": "^3.1.1", "doctrine": "^2.1.0", - "eslint-plugin-eslint-plugin": "^2.1.0", "has": "^1.0.3", "jsx-ast-utils": "^2.2.3", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.1", - "object.values": "^1.1.0", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", "prop-types": "^15.7.2", - "resolve": "^1.13.1" + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" }, "dependencies": { + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -1170,6 +1209,57 @@ "esutils": "^2.0.2" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "jsx-ast-utils": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", @@ -1181,13 +1271,22 @@ } }, "resolve": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", - "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" } + }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } } } }, @@ -1228,9 +1327,9 @@ } }, "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { @@ -1479,14 +1578,15 @@ "dev": true }, "handlebars": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", - "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "requires": { + "minimist": "^1.2.5", "neo-async": "^2.6.0", - "optimist": "^0.6.1", "source-map": "^0.6.1", - "uglify-js": "^3.1.4" + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" } }, "har-schema": { @@ -1520,13 +1620,19 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^1.0.5" } }, "http-signature": { @@ -1541,20 +1647,20 @@ } }, "i18next": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-19.0.2.tgz", - "integrity": "sha512-fBa43Ann2udP1CQAz3IQpOZ1dGAkmi3mMfzisOhH17igneSRbvZ7P2RNbL+L1iRYKMufBmVwnC7G3gqcyviZ9g==", + "version": "19.3.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-19.3.4.tgz", + "integrity": "sha512-ef7AxxutzdhBsBNugE9jgqsbwesG1muJOtZ9ZrPARPs/jXegViTp4+8JCeMp8BAyTIo1Zn0giqc8+2UpqFjU0w==", "requires": { "@babel/runtime": "^7.3.1" } }, - "i18next-node-fs-backend": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/i18next-node-fs-backend/-/i18next-node-fs-backend-2.1.3.tgz", - "integrity": "sha512-CreMFiVl3ChlMc5ys/e0QfuLFOZyFcL40Jj6jaKD6DxZ/GCUMxPI9BpU43QMWUgC7r+PClpxg2cGXAl0CjG04g==", + "i18next-sync-fs-backend": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/i18next-sync-fs-backend/-/i18next-sync-fs-backend-1.1.1.tgz", + "integrity": "sha512-IoJCGid/NLqPFp+2qsumwOy1hG6jENKSIW9BozHL/3ZsjunH0P7iZLRMADljIuFntKlA63suPIPJWGR2SkxLIg==", "requires": { "js-yaml": "3.13.1", - "json5": "2.0.0" + "json5": "0.5.0" } }, "iconv-lite": { @@ -1740,6 +1846,70 @@ } } }, + "internal-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", + "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "has": "^1.0.3", + "side-channel": "^1.0.2" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -1791,6 +1961,12 @@ "is-extglob": "^2.1.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -1806,6 +1982,12 @@ "has": "^1.0.1" } }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -1868,36 +2050,36 @@ "dev": true }, "jsdom": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", - "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", + "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.0.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", "xml-name-validator": "^3.0.0" } }, @@ -1926,19 +2108,9 @@ "dev": true }, "json5": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.0.0.tgz", - "integrity": "sha512-0EdQvHuLm7yJ7lyG5dp7Q3X2ku++BG5ZHaJ5FTnaXpKqDrw4pMxel5Bt3oAYMthnrthFBdnZ1FcsXTPyrQlV0w==", - "requires": { - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } - } + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.0.tgz", + "integrity": "sha1-myBxWwJsvjd4/Xae3M2CLYMypbI=" }, "jsprim": { "version": "1.4.1", @@ -1989,11 +2161,6 @@ "type-check": "~0.3.2" } }, - "line-reader": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/line-reader/-/line-reader-0.4.0.tgz", - "integrity": "sha1-F+RIGNoKwzVnW6MAlU+U72cOZv0=" - }, "load-json-file": { "version": "2.0.0", "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -2014,14 +2181,6 @@ "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { @@ -2052,18 +2211,18 @@ "dev": true }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.43.0" } }, "mimic-fn": { @@ -2082,25 +2241,17 @@ } }, "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "minimist": "^1.2.5" } }, "moment": { @@ -2175,16 +2326,10 @@ "validate-npm-package-license": "^3.0.1" }, "dependencies": { - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, "resolve": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", - "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -2241,21 +2386,9 @@ } }, "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "object.fromentries": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", - "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -2265,9 +2398,9 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", - "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -2317,10 +2450,10 @@ } } }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -2330,9 +2463,9 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", - "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -2382,55 +2515,103 @@ } } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" }, "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } } } }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -2489,9 +2670,15 @@ } }, "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { @@ -2548,12 +2735,6 @@ "find-up": "^2.1.0" } }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -2578,9 +2759,9 @@ } }, "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, "punycode": { @@ -2596,9 +2777,9 @@ "dev": true }, "react-is": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, "read-pkg": { @@ -2627,6 +2808,69 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -2640,9 +2884,9 @@ "dev": true }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2652,7 +2896,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -2662,25 +2906,19 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" }, "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "^1.1.28", + "punycode": "^2.1.1" } } } @@ -2773,12 +3011,12 @@ "dev": true }, "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.0.tgz", + "integrity": "sha512-LXTZygxhf8lfwKaTP/8N9CsVdjTlea3teze4lL6u37ivbgGbV0GGMuNtS/I9rnD/HC2/txUM7Df4S2LVl1qhiA==", "dev": true, "requires": { - "xmlchars": "^2.1.1" + "xmlchars": "^2.2.0" } }, "seed-random": { @@ -2817,6 +3055,69 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "side-channel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", + "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "object-inspect": "^1.7.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -3009,24 +3310,325 @@ } } }, + "string.prototype.matchall": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", + "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.2" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } } }, "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } } }, "strip-bom": { @@ -3085,7 +3687,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -3120,12 +3722,12 @@ } }, "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "^2.1.1" } }, "tslib": { @@ -3177,9 +3779,9 @@ "dev": true }, "uglify-js": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.0.tgz", - "integrity": "sha512-PC/ee458NEMITe1OufAjal65i6lB58R1HWMRcxwvdz1UopW0DYqlRL3xdu3IcTvTXsB02CRHykidkTRL+A3hQA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.1.tgz", + "integrity": "sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw==", "optional": true, "requires": { "commander": "~2.20.3", @@ -3216,9 +3818,9 @@ "dev": true }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "v8-compile-cache": { @@ -3249,29 +3851,27 @@ } }, "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", "dev": true, "requires": { - "browser-process-hrtime": "^0.1.2" + "browser-process-hrtime": "^1.0.0" } }, "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dev": true, "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", "xml-name-validator": "^3.0.0" } }, "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.0.0.tgz", + "integrity": "sha512-jTZAeJnc6D+yAOjygbJOs33kVQIk5H6fj9SFDOhIKjsf9HiAzL/c+tAJsc8ASWafvhNkH+wJZms47pmajkhatA==", "dev": true }, "whatwg-encoding": { @@ -3290,14 +3890,22 @@ "dev": true }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.0.0.tgz", + "integrity": "sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "^2.0.0", + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } } }, "word-wrap": { @@ -3307,9 +3915,9 @@ "dev": true }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "wrappy": { "version": "1.0.2", @@ -3327,13 +3935,10 @@ } }, "ws": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz", - "integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==", - "dev": true, - "requires": { - "async-limiter": "^1.0.0" - } + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index b337a75..2322f8a 100644 --- a/package.json +++ b/package.json @@ -25,20 +25,20 @@ "repositoryUrl": "https://github.com/cerner/cucumber-forge-report-generator.git" }, "dependencies": { - "handlebars": "^4.5.3", - "i18next": "^19.0.2", - "i18next-node-fs-backend": "^2.1.3", - "line-reader": "^0.4.0", + "directory-tree": "^2.2.4", + "handlebars": "^4.7.6", + "i18next": "^19.3.4", + "i18next-sync-fs-backend": "^1.1.1", "moment": "^2.24.0" }, "devDependencies": { "chai": "^4.2.0", "cucumber": "^6.0.5", "eslint": "^6.8.0", - "eslint-config-airbnb-base": "^14.0.0", - "eslint-plugin-import": "^2.19.1", + "eslint-config-airbnb-base": "^14.1.0", + "eslint-plugin-import": "^2.20.2", "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-react": "^7.17.0", - "jsdom": "^15.2.1" + "eslint-plugin-react": "^7.19.0", + "jsdom": "^16.2.2" } } diff --git a/src/Generator.js b/src/Generator.js index 197846e..d051bad 100644 --- a/src/Generator.js +++ b/src/Generator.js @@ -1,14 +1,11 @@ +const dirTree = require('directory-tree'); const fs = require('fs'); const handlebars = require('handlebars'); const i18n = require('i18next'); -const i18nBackend = require('i18next-node-fs-backend'); -const linereader = require('line-reader'); +const i18nBackend = require('i18next-sync-fs-backend'); const moment = require('moment'); const os = require('os'); const path = require('path'); -const util = require('util'); - -const eachLine = util.promisify(linereader.eachLine); const FILE_ENCODING = 'utf-8'; const LANGUAGE = 'en'; @@ -16,6 +13,7 @@ const TEMPLATESDIR = 'templates'; const DEFAULT_REPORT_NAME = 'All Scenarios'; let author; +let sidenavButtonsTemplate; let docHbTemplate; let featureHbTemplate; let cssStyles; @@ -26,6 +24,7 @@ let cog; let projectName = 'Feature documentation'; let reportName = DEFAULT_REPORT_NAME; let tagFilter = null; +let idSequence = 1; const lineStartsWithI18n = (line, i18nkey) => line.startsWith(i18n.t(i18nkey)); @@ -33,29 +32,23 @@ const stepStarting = (line) => lineStartsWithI18n(line, 'given') || lineStartsWi || lineStartsWithI18n(line, 'then') || lineStartsWithI18n(line, 'and') || lineStartsWithI18n(line, 'but') || line.trim().startsWith('*'); -const createScenario = (name, tags) => { - const scenario = {}; - scenario.name = name; - scenario.description = ''; - scenario.tags = tags; - scenario.steps = []; - return scenario; -}; +const createScenario = (name, tags) => ({ + name, + description: '', + tags, + steps: [], +}); -const createExamples = (line) => { - const examples = {}; - examples.name = line; - examples.table = []; - return examples; -}; +const createExamples = (name) => ({ + name, + table: [], +}); -const createStep = (name) => { - const step = {}; - step.name = name; - step.table = []; - step.docString = ''; - return step; -}; +const createStep = (name) => ({ + name, + table: [], + docString: '', +}); const getNewPhase = (line) => { if (lineStartsWithI18n(line, 'feature')) { @@ -79,16 +72,22 @@ const getNewPhase = (line) => { return null; }; -const parseFeatureFile = async (featureFilename) => { - const feature = {}; - feature.scenarios = []; - feature.tags = []; - feature.description = ''; +const getFeatureFromFile = (featureFilename) => { + const feature = { + scenarios: [], + tags: [], + description: '', + }; let scenario = null; let tags = []; let currentPhase = null; - await eachLine(featureFilename, (nextLine) => { + + const fileLines = fs + .readFileSync(featureFilename, FILE_ENCODING) + .replace('\r\n', '\n') + .split('\n'); + fileLines.forEach((nextLine) => { const line = nextLine.trim(); const newPhase = getNewPhase(line); if (currentPhase === 'DOC_STRING_STARTED') { @@ -133,7 +132,9 @@ const parseFeatureFile = async (featureFilename) => { // We want to skip any comment lines. } else if (line.startsWith('|')) { const step = scenario.steps[scenario.steps.length - 1]; - const lines = line.split('|').filter((entry) => entry).map((entry) => entry.trim()); + const lines = line + .split('|') + .filter((entry) => entry).map((entry) => entry.trim()); switch (currentPhase) { case 'EXAMPLES_STARTED': scenario.examples.table.push(lines); @@ -167,48 +168,86 @@ const getFilteredScenarios = (scenarios) => scenarios.map((scenario) => { return undefined; }).filter((scenario) => scenario); -const getFilteredFeatures = (features) => { - const filteredFeatures = []; - features.forEach((feature) => { +const populateHtmlIdentifiers = (feature) => { + feature.featureId = idSequence; + idSequence += 1; + feature.featureWrapperId = idSequence; + idSequence += 1; + feature.scenarios.forEach((scenario) => { + scenario.scenarioId = idSequence; + idSequence += 1; + scenario.scenarioButtonId = idSequence; + idSequence += 1; + }); +}; + +const populateTagStrings = (feature) => { + feature.tagString = ''; + feature.tags.forEach((tag) => { feature.tagString += `${tag} `; }); + feature.scenarios.forEach((scenario) => { + scenario.tagString = ''; + scenario.tags.forEach((tag) => { scenario.tagString += `${tag} `; }); + }); +}; + +// eslint-disable-next-line no-unused-vars +const parseFeatureFile = (item, nodePath, fsStats) => { + let feature = getFeatureFromFile(item.path); + + if (tagFilter) { const filteredScenarios = getFilteredScenarios(feature.scenarios); if (filteredScenarios.length > 0) { feature.scenarios = filteredScenarios; - filteredFeatures.push(feature); + } else { + feature = undefined; } - }); - return filteredFeatures; + } + if (feature) { + item.feature = feature; + populateHtmlIdentifiers(feature); + populateTagStrings(feature); + } }; -const parseFeatures = async (files) => { - const featureFiles = files; - const sortedFeatureFiles = featureFiles.sort(); - return Promise.all(sortedFeatureFiles.map(parseFeatureFile)); +const pruneFeatureFileTree = (featureFileTree) => { + featureFileTree.children = featureFileTree.children + .filter((child) => child.type === 'file' || pruneFeatureFileTree(child)); + return featureFileTree.children.length > 0; }; -const populateHtmlIdentifiers = (features) => { - let featureCount = 0; - features.forEach((feature) => { - feature.featureId = `feature${featureCount}`; - feature.featureWrapperId = `featureWrapper${featureCount}`; - let scenarioCount = 0; - feature.scenarios.forEach((scenario) => { - scenario.scenarioId = `${feature.featureId}Scenario${scenarioCount}`; - scenario.scenarioButtonId = `${feature.featureId}ScenarioButton${scenarioCount}`; - scenarioCount += 1; - }); - featureCount += 1; - }); +const getFeatureFileTree = (directoryPath) => { + let featureFileTree = dirTree(directoryPath, { + extensions: /\.feature/, + exclude: /node_modules|target/, + }, parseFeatureFile); + // Prune the tree so it only contains the feature files and the directories that contain them + pruneFeatureFileTree(featureFileTree); + + // Reduce directories at the root of the tree if they only have a single child that is a directory + while (featureFileTree.children.length === 1 && featureFileTree.children[0].type === 'directory') { + // Only advance if new root has no feature children + // (top-level elements should only be directories) + const [newRoot] = featureFileTree.children; + if (!newRoot.children.filter((child) => child.type === 'file').length) { + featureFileTree = newRoot; + } else { + break; + } + } + + return featureFileTree; }; -const populateTagStrings = (features) => { - features.forEach((feature) => { - feature.tagString = ''; - feature.tags.forEach((tag) => { feature.tagString += `${tag} `; }); - feature.scenarios.forEach((scenario) => { - scenario.tagString = ''; - scenario.tags.forEach((tag) => { scenario.tagString += `${tag} `; }); - }); +const getFeaturesHtml = (featureFileTree) => { + let featuresHtml = ''; + featureFileTree.children.forEach((child) => { + if (child.type === 'file') { + featuresHtml += featureHbTemplate(child.feature); + } else if (child.type === 'directory') { + featuresHtml += getFeaturesHtml(child); + } }); + return featuresHtml; }; const trimCucumberKeywords = (name, ...i18nkeys) => { @@ -218,56 +257,82 @@ const trimCucumberKeywords = (name, ...i18nkeys) => { return name.slice(charsToTrim).trim(); }; -const getFeatureButtons = (features) => { +const getFeatureButtons = (featureFileTree) => { const featureButtons = []; - - features.forEach((feature) => { - const featureButton = {}; - featureButton.featureId = feature.featureId; - featureButton.featureWrapperId = feature.featureWrapperId; - featureButton.title = trimCucumberKeywords(feature.name, 'feature'); - featureButton.scenarioButtons = []; - feature.scenarios.forEach((scenario) => { - const scenarioButton = {}; - scenarioButton.id = scenario.scenarioButtonId; - scenarioButton.scenarioId = scenario.scenarioId; - scenarioButton.title = trimCucumberKeywords(scenario.name, 'scenario', 'scenario_outline'); - featureButton.scenarioButtons.push(scenarioButton); + featureFileTree.children + .filter((child) => child.type === 'file') + .forEach((child) => { + const { feature } = child; + const featureButton = { + featureId: feature.featureId, + featureWrapperId: feature.featureWrapperId, + title: trimCucumberKeywords(feature.name, 'feature'), + scenarioButtons: [], + }; + feature.scenarios.forEach((scenario) => { + featureButton.scenarioButtons.push({ + id: scenario.scenarioButtonId, + scenarioId: scenario.scenarioId, + title: trimCucumberKeywords(scenario.name, 'scenario', 'scenario_outline'), + }); + }); + featureButtons.push(featureButton); }); - featureButtons.push(featureButton); - }); return featureButtons; }; -const create = async (files) => { - const features = await parseFeatures(files); - const filteredFeatures = tagFilter ? getFilteredFeatures(features) : features; - populateHtmlIdentifiers(filteredFeatures); - populateTagStrings(filteredFeatures); +const getDirectoryButtonHtml = (featureFileTree) => { + const sidenavData = { + title: featureFileTree.name, + featureButtons: getFeatureButtons(featureFileTree), + sidenavButtonsHtml: '', + }; - let featuresHtml = ''; - filteredFeatures.forEach((filteredFeature) => { - featuresHtml += featureHbTemplate(filteredFeature); - }); + featureFileTree.children + .filter((child) => child.type === 'directory') + .forEach((child) => { sidenavData.sidenavButtonsHtml += getDirectoryButtonHtml(child); }); - const docData = {}; - docData.cssStyles = cssStyles; - docData.scripts = scripts; - docData.logo = logo; - docData.cog = cog; - docData.creationdate = moment().format('LL'); - docData.author = author; - docData.reportName = reportName; - docData.projectName = projectName; - docData.featuresHtml = featuresHtml; - docData.featureButtons = getFeatureButtons(filteredFeatures); - return docHbTemplate(docData); + return sidenavButtonsTemplate(sidenavData); +}; + +const getSidenavButtonsHtml = (featureFileTree) => { + let buttonsHtml = ''; + // If the top level directory contains feature files, run on the top-level and not the children. + if (featureFileTree.children.filter((child) => child.type === 'file').length > 0) { + buttonsHtml = getDirectoryButtonHtml(featureFileTree); + } else { + featureFileTree.children.forEach((child) => { buttonsHtml += getDirectoryButtonHtml(child); }); + } + return buttonsHtml; +}; + +const create = (directoryPath) => { + const featureFileTree = getFeatureFileTree(directoryPath); + if (featureFileTree.children.length === 0) { + throw new Error('No feature files were found in the given directory.'); + } + return docHbTemplate({ + cssStyles, + scripts, + logo, + cog, + creationdate: moment().format('LL'), + author, + reportName, + projectName, + featuresHtml: getFeaturesHtml(featureFileTree), + sidenavButtonsHtml: getSidenavButtonsHtml(featureFileTree), + }); }; class Generator { constructor() { author = os.userInfo().username; + const sidenavButtonsTemplatePath = path + .resolve(__dirname, TEMPLATESDIR, 'sidenav_buttons_template.html'); + sidenavButtonsTemplate = handlebars + .compile(fs.readFileSync(sidenavButtonsTemplatePath, FILE_ENCODING)); const docTemplatePath = path.resolve(__dirname, TEMPLATESDIR, 'doc_template.html'); docHbTemplate = handlebars.compile(fs.readFileSync(docTemplatePath, FILE_ENCODING)); const featureTemplatePath = path.resolve(__dirname, TEMPLATESDIR, 'feature_template.html'); @@ -279,7 +344,10 @@ class Generator { } // eslint-disable-next-line class-methods-use-this - async generate(files = [], name = null, tag = null) { + generate(directoryPath, name = null, tag = null) { + if (!directoryPath) { + throw new Error('A feature directory path must be provided.'); + } if (name) { projectName = name.trim(); } @@ -294,13 +362,14 @@ class Generator { reportName = DEFAULT_REPORT_NAME; } i18n.use(i18nBackend); - await i18n.init({ + i18n.init({ lng: LANGUAGE, + initImmediate: false, backend: { loadPath: `${__dirname}/locales/{{lng}}/{{ns}}.json`, }, }); - return create(files); + return create(directoryPath); } } diff --git a/src/templates/doc_template.html b/src/templates/doc_template.html index 7e85be1..6a4ae6b 100644 --- a/src/templates/doc_template.html +++ b/src/templates/doc_template.html @@ -17,19 +17,10 @@
{{author}} - {{creationdate}}
-
- {{#each featureButtons}} - -
- {{#each this.scenarioButtons}} - - {{/each}} -
- {{/each}} +
+
    + {{{sidenavButtonsHtml}}} +
diff --git a/src/templates/feature_template.html b/src/templates/feature_template.html index 7cdf804..9a7eb5f 100644 --- a/src/templates/feature_template.html +++ b/src/templates/feature_template.html @@ -17,7 +17,7 @@

{{this.background.name}}

{{this.name}}

{{#if this.table.length}}
- +
{{#each this.table}} {{#each this}} @@ -51,7 +51,7 @@

{{this.name}}

{{this.name}}

{{#if this.table.length}}
-
+
{{#each this.table}} {{#each this}} @@ -70,7 +70,7 @@

{{this.name}}

{{this.examples.name}}

{{#if this.examples.table.length}}
-
+
{{#each this.examples.table}} {{#if @first}} diff --git a/src/templates/scripts.js b/src/templates/scripts.js index 2aedfdb..b75d668 100644 --- a/src/templates/scripts.js +++ b/src/templates/scripts.js @@ -15,24 +15,14 @@ const toggleFunctionAccordion = (element) => { element.classList.toggle('active'); const icon = element.getElementsByTagName('i')[0]; const panel = element.nextElementSibling; - if (panel.style.maxHeight) { - panel.style.maxHeight = null; - icon.classList.remove('fa-angle-down'); - icon.classList.add('fa-angle-right'); - } else { - panel.style.maxHeight = `${panel.scrollHeight}px`; - // Close all the other panels - Array.from(document.getElementsByClassName('feature-button')).forEach((featureButton) => { - if (element !== featureButton) { - featureButton.classList.remove('active'); - featureButton.nextElementSibling.style.maxHeight = null; - const iconToClose = featureButton.getElementsByTagName('i')[0]; - iconToClose.classList.remove('fa-angle-down'); - iconToClose.classList.add('fa-angle-right'); - } - }); + panel.classList.toggle('active'); + + if (panel.classList.contains('active')) { icon.classList.add('fa-angle-down'); icon.classList.remove('fa-angle-right'); + } else { + icon.classList.remove('fa-angle-down'); + icon.classList.add('fa-angle-right'); } }; @@ -106,19 +96,62 @@ const toggleDisplayedFeature = (element) => { }); }; +const toggleDirectoryButton = (element) => { + element.classList.toggle('active'); + const icon = element.getElementsByTagName('i')[0]; + const panel = element.nextElementSibling; + panel.classList.toggle('active'); + + if (panel.classList.contains('active')) { + icon.classList.remove('fa-folder'); + icon.classList.add('fa-folder-open'); + } else { + icon.classList.add('fa-folder'); + icon.classList.remove('fa-folder-open'); + } +}; + +const toggleParentDirectoryButtons = (element) => { + toggleDirectoryButton(element); + + // Recuse on any directory buttons above + const parentDirectoryButton = element.parentNode.parentNode.previousElementSibling; + if (parentDirectoryButton && parentDirectoryButton.classList.contains('directory-button')) { + toggleParentDirectoryButtons(parentDirectoryButton); + } +}; + const init = () => { + // Add listeners for directory buttons + Array.from(document.getElementsByClassName('directory-button')).forEach((directoryButton) => { + directoryButton.addEventListener('click', function click() { + toggleDirectoryButton(this); + }); + }); + // Add listeners for feature buttons Array.from(document.getElementsByClassName('feature-button')).forEach((featureButton) => { featureButton.addEventListener('click', function click() { toggleFunctionAccordion(this); - toggleDisplayedFeature(this); - scrollTo(this); + if (this.classList.contains('active')) { + toggleDisplayedFeature(this); + scrollTo(this); + + // Toggle the first scenario button of the feature + const scenarioButton = this.nextElementSibling.getElementsByTagName('button')[0]; + toggleScenarioButton(scenarioButton); + } }); }); // Add listeners for scenario buttons Array.from(document.getElementsByClassName('scenario-button')).forEach((scenarioButton) => { scenarioButton.addEventListener('click', function click() { + // Make sure the scenario's feature is active + const featureButton = this.parentNode.parentNode.previousElementSibling; + if (!this.classList.contains('active')) { + toggleDisplayedFeature(featureButton); + } toggleScenarioButton(this); scrollTo(this); }); @@ -140,6 +173,10 @@ const init = () => { // Open the first feature. const firstFeatureButton = document.getElementsByClassName('feature-button')[0]; if (firstFeatureButton) { + // Open any parent directory buttons + const directoryButton = firstFeatureButton.parentNode.parentNode.previousElementSibling; + toggleParentDirectoryButtons(directoryButton); + toggleFunctionAccordion(firstFeatureButton); toggleDisplayedFeature(firstFeatureButton); } diff --git a/src/templates/sidenav_buttons_template.html b/src/templates/sidenav_buttons_template.html new file mode 100644 index 0000000..f0bb448 --- /dev/null +++ b/src/templates/sidenav_buttons_template.html @@ -0,0 +1,25 @@ +
  • + +
      + {{{sidenavButtonsHtml}}} + {{#each featureButtons}} +
    • + +
        + {{#each this.scenarioButtons}} +
      • + +
      • + {{/each}} +
      +
    • + {{/each}} +
    +
  • + \ No newline at end of file diff --git a/src/templates/style.css b/src/templates/style.css index af017af..6aa3d77 100644 --- a/src/templates/style.css +++ b/src/templates/style.css @@ -1,195 +1,177 @@ @import url('https://fonts.googleapis.com/css?family=Lato|Roboto+Mono|Roboto+Slab'); @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css'); +/* Global style */ html { - scroll-behavior: smooth; font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; - font-weight: normal; - font-style: normal; font-size: medium; + font-style: normal; + font-weight: normal; + scroll-behavior: smooth; } body { - margin: 0px; background-color: #fcfcfc; -} -pre { - overflow-x: auto; -} -a.anchor { - display: block; - position: relative; - top: -1.5em; -} - -.table-wrapper { - width: calc(70vw - 4em); - overflow-x: auto; -} -table { - border-collapse: collapse; - margin-left: 1em; - white-space: nowrap; -} -table, th, td { - border: 1px solid black; -} -.step-table td, .example-table td, .example-table th { - padding: 5px; + margin: 0px; } /* Sidebar Style */ .sidenav { - width: 30vw; - height: 100%; - position: fixed; - z-index: 1; background-color: #272525; - overflow-x: hidden; color: #f1f1f1; + height: 100%; + overflow-x: hidden; + position: fixed; text-align: center; + width: 30vw; + z-index: 1; /* Disable the scroll bar */ scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* IE 10+ */ } +/* Disable the scroll bar */ .sidenav::-webkit-scrollbar { /* WebKit */ width: 0; height: 0; } -.sidenav-body { - min-height: 100%; - margin-top: 7em; - margin-bottom: 2em; -} #sidenav-header { - width: 30vw; - position: fixed; color: #3a7ca8; font-weight: bold; line-height: 1.5em; + position: fixed; + width: 30vw; } #sidenavTitle { - color: #f1f1f1; background-color: #2980B9; + color: #f1f1f1; padding: 1em 0.01em 1em 0.01em; } #sidenavTitle h1 { font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; - font-weight: bold; font-size: xx-large; + font-weight: bold; margin: 0em; } #sidenav-subheader { background-color: #272525; padding: 0.25em 0em 0.25em 0em; } -#sidenavFooter { - position: fixed; - bottom: 0; - width: 30vw; - text-align: left; - padding: 0.25em 0em 0.25em 0em; - background-color: #272525; +#sidenav-body { + background-color: #404040; + margin-bottom: 2em; + margin-top: 7em; + min-height: 100%; } -#settingsDrawer { - padding: 0.5em 0.5em 0.5em 0.5em; +#sidenav-body ul { display: none; + list-style-type: none; + padding-left: 0.5em; } -#settingsDrawer.active { +#sidenav-body ul.active, #sidenav-body > ul { display: block; } -#settingsDrawer p { - color: grey; +#sidenav-body button { + cursor: pointer; + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; + outline: none; + padding: 0.25em; + text-align: left; + white-space: nowrap; + width: 100%; } -#settingsDrawer a { - color: grey; +.directory-button { + background-color: #404040; + border: none; + color: #a9a9a9; + padding-left: 0em; } -#settingsButton { - padding: 0.25em; - margin-left: 0.25em; - cursor: pointer; - vertical-align: middle; +.directory-button.active, .directory-button:hover { + color: white; } -#footerTitle { - color: #3a7ca8; - margin-left: calc(15vw - 6.25em); +i.fa-folder, i.fa-folder-open { + width: 1.5em; } .feature-button { - font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; background-color: #404040; - color: #d9d9d9; - cursor: pointer; - padding: 0.75em; - width: 100%; - text-align: left; + border-bottom-left-radius: 0.85em; + border-top-left-radius: 0.25em; border: none; - outline: none; - white-space: nowrap; + color: #a9a9a9; } .feature-button.active, .feature-button:hover { background-color: #fcfcfc; - font-weight: bold; - color: #404040; border-bottom: solid 1px #c9c9c9; + color: #404040; + font-weight: bold; + margin-bottom: -1px; +} +.feature-button:hover:not(.active) { + border-bottom-left-radius: 0.25em; } i.fa-angle-right, i.fa-angle-down { width: 0.6em; } -.panel { - max-height: 0; - overflow: hidden; - transition: max-height 0.2s ease-out; -} .scenario-button { - font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; background-color: #e2e2e2; - color: #404040; - cursor: pointer; - padding: 0.5em; - width: 100%; - text-align: left; - outline: none; - white-space: nowrap; - border-top: none; - border-left: none; border-bottom: none; + border-left: none; border-right: solid 1px #c9c9c9; + border-top: none; + color: #404040; } .scenario-button.active, .scenario-button:hover { background-color: #ccc; } +.scenario-button.last { + border-bottom-left-radius: 0.85em; +} .scenario-button span { - margin-left: 1em; + margin-left: 0.25em; +} +#sidenavFooter { + background-color: #272525; + bottom: 0; + padding: 0.25em 0em 0.25em 0em; + position: fixed; + text-align: left; + width: 30vw; +} +#settingsDrawer { + display: none; + padding: 0.5em 0.5em 0.5em 0.5em; +} +#settingsDrawer.active { + display: block; +} +#settingsDrawer p { + color: grey; +} +#settingsDrawer a { + color: grey; +} +#settingsButton { + cursor: pointer; + margin-left: 0.25em; + padding: 0.25em; + vertical-align: middle; +} +#footerTitle { + color: #3a7ca8; + margin-left: calc(15vw - 6.25em); } /* Main Content Window Style */ .main { - margin-left: 30vw; margin-bottom: 75vh; + margin-left: 30vw; padding: 0px 10px; } .main h2 { - padding-top: 0.5em; - margin-top: 0em; - margin-bottom: 0.5em; font-family: 'Roboto Slab', sans-serif; - font-weight: bold; font-size: x-large; -} -.main h3 { - margin-top: 1em; - margin-bottom: 0em; - font-family: 'Roboto Slab', sans-serif; font-weight: bold; - font-size: large; -} -.main pre, .main p { - margin-top: 0.5em; margin-bottom: 0.5em; - font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; - font-size: medium; -} -.scenario-description { - margin-bottom: 1.5em; + margin-top: 0em; + padding-top: 0.5em; } .feature-wrapper { display: none; @@ -197,12 +179,44 @@ i.fa-angle-right, i.fa-angle-down { .feature-wrapper.active { display: block; } +.feature-wrapper a.anchor { + display: block; + position: relative; + top: -1.5em; +} +.tags { + color: grey; + display: none; + margin-bottom: -1em; +} +.tags.active { + display: block; +} .feature-body { margin-left: 1em; } +.feature-body h3 { + font-family: 'Roboto Slab', sans-serif; + font-size: large; + font-weight: bold; + margin-bottom: 0em; + margin-top: 1em; +} +.feature-body pre, .feature-body p { + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; + font-size: medium; + margin-bottom: 0.5em; + margin-top: 0.5em; +} +.feature-body pre { + overflow-x: auto; +} .scenario-body { margin-left: 1em; } +.scenario-description { + margin-bottom: 1.5em; +} .docstring { margin-left: 1em; } @@ -210,16 +224,21 @@ i.fa-angle-right, i.fa-angle-down { font-family: 'Roboto Mono', monospace; font-size: small; } -.scenario-divider { - margin-top: 1em; - border: 0; - border-bottom: 1px dashed #ccc; +.table-wrapper { + overflow-x: auto; + width: calc(70vw - 4em); } -.tags { - color: grey; - margin-bottom: -1em; - display: none; +.table-wrapper table { + border-collapse: collapse; + margin-left: 1em; + white-space: nowrap; } -.tags.active { - display: block; +.table-wrapper table, th, td { + padding: 5px; + border: 1px solid black; +} +.scenario-divider { + border-bottom: 1px dashed #ccc; + border: 0; + margin-top: 1em; }