From 2f835ac09edf49087750665015a1f35ef94e84ae Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Sat, 15 Oct 2022 07:43:42 +0200 Subject: [PATCH] chore: migrate to cypress for ui e2e (#3434) --- .gitignore | 4 + e2e/README.md | 2 +- e2e/ui/.eslintrc | 9 - e2e/ui/CHANGELOG.md | 29 -- e2e/ui/README.md | 4 + e2e/ui/basic.spec.js | 64 --- e2e/ui/cypress.config.ts | 60 +++ e2e/ui/cypress/e2e/home.cy.ts | 30 ++ e2e/ui/cypress/e2e/publish.cy.ts | 88 ++++ e2e/ui/cypress/e2e/signin.cy.ts | 31 ++ e2e/ui/cypress/support/commands.ts | 37 ++ e2e/ui/cypress/support/e2e.ts | 19 + e2e/ui/helper.ts | 36 -- e2e/ui/jest.config.js | 8 - e2e/ui/package.json | 8 +- e2e/ui/publish.spec.js | 118 ----- e2e/ui/sigin.spec.js | 80 ---- e2e/ui/tsconfig.json | 18 + .../Dependencies/Dependencies.tsx | 3 +- .../DetailContainer/NoItems/NoItems.tsx | 5 +- .../DetailContainer/UpLinks/UpLinks.tsx | 2 +- .../__snapshots__/UpLinks.test.tsx.snap | 2 + .../DetailContainer/Versions/Versions.tsx | 3 +- .../Versions/VersionsHistoryList.tsx | 2 +- .../Versions/VersionsTagList.tsx | 2 +- .../src/pages/home/PackageList/Help/Help.tsx | 2 +- .../Help/__snapshots__/Help.test.tsx.snap | 1 + .../home/PackageList/Package/Package.tsx | 4 +- packages/tools/eslint/package.json | 1 + packages/tools/eslint/src/index.js | 9 +- packages/tools/eslint/src/rules/cypress.js | 3 + pnpm-lock.yaml | 452 ++++++++++++++---- 32 files changed, 688 insertions(+), 448 deletions(-) delete mode 100644 e2e/ui/.eslintrc delete mode 100644 e2e/ui/CHANGELOG.md delete mode 100644 e2e/ui/basic.spec.js create mode 100644 e2e/ui/cypress.config.ts create mode 100644 e2e/ui/cypress/e2e/home.cy.ts create mode 100644 e2e/ui/cypress/e2e/publish.cy.ts create mode 100644 e2e/ui/cypress/e2e/signin.cy.ts create mode 100644 e2e/ui/cypress/support/commands.ts create mode 100644 e2e/ui/cypress/support/e2e.ts delete mode 100644 e2e/ui/helper.ts delete mode 100644 e2e/ui/jest.config.js delete mode 100644 e2e/ui/publish.spec.js delete mode 100644 e2e/ui/sigin.spec.js create mode 100644 e2e/ui/tsconfig.json create mode 100644 packages/tools/eslint/src/rules/cypress.js diff --git a/.gitignore b/.gitignore index 8b18594f3..1685df997 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,7 @@ website/docs/api/**/*.md website/docs/api/**/*.yml !website/docs/api/index.md packages/**/docs + +# cypress +e2e/ui/cypress/videos/**/* +e2e/ui/cypress/screenshots/**/* diff --git a/e2e/README.md b/e2e/README.md index acc25ad68..690a4594e 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -3,4 +3,4 @@ This folder is composed of two strategies: - E2E for CLI -- E2E for the UI (puppeteer) +- E2E for the UI (cypress) diff --git a/e2e/ui/.eslintrc b/e2e/ui/.eslintrc deleted file mode 100644 index 619523212..000000000 --- a/e2e/ui/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "globals": { - "VERDACCIO_API_URL": true, - "__DEBUG__": true - }, - "env": { - "browser": true - } -} diff --git a/e2e/ui/CHANGELOG.md b/e2e/ui/CHANGELOG.md deleted file mode 100644 index 1a2d942a5..000000000 --- a/e2e/ui/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# @verdaccio/e2e-ui - -## 2.0.0-6-next.3 - -### Major Changes - -- 000d4374: feat: upgrade to material ui 5 - -## 1.1.0-6-next.2 - -### Minor Changes - -- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications - -## 1.1.0-6-next.1 - -### Minor Changes - -- 1b217fd3: Some verdaccio modules depend on 'mkdirp' library which provides recursive directory creation functionality. - NodeJS can do this out of the box since v.10.12. The last commit in 'mkdirp' was made in early 2016, and it's mid 2021 now. - Time to stick with a built-in library solution! - - - All 'mkdirp' calls are replaced with appropriate 'fs' calls. - -## 1.0.1-alpha.0 - -### Patch Changes - -- fecbb9be: chore: add release step to private regisry on merge changeset pr diff --git a/e2e/ui/README.md b/e2e/ui/README.md index d409f2b45..3f131384d 100644 --- a/e2e/ui/README.md +++ b/e2e/ui/README.md @@ -7,3 +7,7 @@ - Check navigation - Check sidebar - Check protected packages works + +## Contribute + +More tests could be added to verify UI works as expected. diff --git a/e2e/ui/basic.spec.js b/e2e/ui/basic.spec.js deleted file mode 100644 index 901888c03..000000000 --- a/e2e/ui/basic.spec.js +++ /dev/null @@ -1,64 +0,0 @@ -const { join } = require('path'); -const { fileUtils } = require('@verdaccio/core'); -const { parseConfigFile } = require('@verdaccio/config'); -const { Registry, ServerQuery } = require('verdaccio'); - -describe('basic functionality', () => { - let registry1; - let page; - beforeAll(async () => { - const configProtected = parseConfigFile(join(__dirname, './config/config.yaml')); - const registry1storage = await fileUtils.createTempStorageFolder('storage-1'); - const protectedRegistry = await Registry.fromConfigToPath({ - ...configProtected, - storage: registry1storage, - }); - registry1 = new Registry(protectedRegistry.configPath); - await registry1.init(); - - const query1 = new ServerQuery(registry1.getRegistryUrl()); - await query1.createUser('test', 'test'); - - page = await global.__BROWSER__.newPage(); - await page.goto(`http://0.0.0.0:${registry1.getPort()}`); - // eslint-disable-next-line no-console - page.on('console', (msg) => console.log('PAGE LOG:', msg.text())); - }); - - afterAll(async () => { - await page.close(); - registry1.stop(); - }); - - // this might be increased based on the delays included in all test - jest.setTimeout(20000); - - test('should display title', async () => { - const text = await page.title(); - await page.waitForTimeout(1000); - - expect(text).toContain('verdaccio-server-e2e'); - }); - - test('should match title with no packages published', async () => { - const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent); - expect(text).toMatch('No Package Published Yet.'); - }); - - test('should match title with first step', async () => { - const text = await page.evaluate(() => document.querySelector('#help-card').textContent); - expect(text).toContain(`npm adduser --registry http://0.0.0.0:${registry1.getPort()}`); - }); - - test('should match title with second step', async () => { - const text = await page.evaluate(() => document.querySelector('#help-card').textContent); - expect(text).toContain(`npm publish --registry http://0.0.0.0:${registry1.getPort()}`); - }); - - test('should go to 404 page', async () => { - await page.goto(`http://0.0.0.0:${registry1.getPort()}/-/web/detail/@verdaccio/not-found`); - await page.waitForTimeout(500); - const text = await page.evaluate(() => document.querySelector('.not-found-text').textContent); - expect(text).toMatch("Sorry, we couldn't find it..."); - }); -}); diff --git a/e2e/ui/cypress.config.ts b/e2e/ui/cypress.config.ts new file mode 100644 index 000000000..3c6154be7 --- /dev/null +++ b/e2e/ui/cypress.config.ts @@ -0,0 +1,60 @@ +import { defineConfig } from 'cypress'; +import { join } from 'path'; +import { Registry, ServerQuery } from 'verdaccio'; + +import { parseConfigFile } from '@verdaccio/config'; +import { HEADERS, fileUtils } from '@verdaccio/core'; +import { generatePackageMetadata } from '@verdaccio/test-helper'; + +let registry1; +export default defineConfig({ + e2e: { + setupNodeEvents(on) { + on('before:run', async () => { + const configProtected = parseConfigFile(join(__dirname, './config/config.yaml')); + const registry1storage = await fileUtils.createTempStorageFolder('storage-1'); + const protectedRegistry = await Registry.fromConfigToPath({ + ...configProtected, + storage: registry1storage, + }); + registry1 = new Registry(protectedRegistry.configPath, { + createUser: true, + credentials: { user: 'test', password: 'test' }, + }); + await registry1.init(); + }); + + on('after:run', async () => { + registry1.stop(); + }); + + on('task', { + publishScoped() { + const scopedPackageMetadata = generatePackageMetadata('pkg-scoped', '1.0.6'); + const server = new ServerQuery(registry1.getRegistryUrl()); + server + .putPackage(scopedPackageMetadata.name, scopedPackageMetadata, { + [HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`, + }) + .then(() => {}); + return null; + }, + publishProtected({ pkgName }) { + const protectedPackageMetadata = generatePackageMetadata(pkgName, '5.0.5'); + const server = new ServerQuery(registry1.getRegistryUrl()); + server + .putPackage(protectedPackageMetadata.name, protectedPackageMetadata, { + [HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`, + }) + .then(() => {}); + }, + registry() { + return { + registryUrl: registry1.getRegistryUrl(), + port: registry1.getPort(), + }; + }, + }); + }, + }, +}); diff --git a/e2e/ui/cypress/e2e/home.cy.ts b/e2e/ui/cypress/e2e/home.cy.ts new file mode 100644 index 000000000..806b36cd6 --- /dev/null +++ b/e2e/ui/cypress/e2e/home.cy.ts @@ -0,0 +1,30 @@ +describe('home spec', () => { + let ctx: any = {}; + beforeEach(async () => { + // @ts-expect-error + const registry = await cy.task('registry'); + ctx.url = registry.registryUrl; + }); + + it('title should be correct', () => { + cy.visit(ctx.url); + cy.location('pathname').should('include', '/'); + cy.title().should('eq', 'verdaccio-server-e2e'); + }); + + it('should match title with no packages published', () => { + cy.visit(ctx.url); + cy.getByTestId('help-card').contains('No Package Published Yet.'); + }); + + it('should display instructions on help card', () => { + cy.visit(ctx.url); + cy.getByTestId('help-card').contains(`npm adduser --registry ${ctx.url}`); + cy.getByTestId('help-card').contains(`npm publish --registry ${ctx.url}`); + }); + + it('should go to 404 page', () => { + cy.visit(`${ctx.url}/-/web/detail/@verdaccio/not-found`); + cy.getByTestId('404').contains(`Sorry, we couldn't find it.`); + }); +}); diff --git a/e2e/ui/cypress/e2e/publish.cy.ts b/e2e/ui/cypress/e2e/publish.cy.ts new file mode 100644 index 000000000..11604243d --- /dev/null +++ b/e2e/ui/cypress/e2e/publish.cy.ts @@ -0,0 +1,88 @@ +describe('publish spec', () => { + let ctx: any = {}; + const credentials = { user: 'test', password: 'test' }; + beforeEach(async () => { + // @ts-expect-error + const registry = await cy.task('registry'); + ctx.url = registry.registryUrl; + cy.intercept('POST', '/-/verdaccio/sec/login').as('sign'); + cy.intercept('GET', '/-/verdaccio/data/packages').as('pkgs'); + cy.intercept('GET', '/-/verdaccio/data/sidebar/pkg-scoped').as('sidebar'); + cy.intercept('GET', '/-/verdaccio/data/package/readme/pkg-scoped').as('readme'); + cy.task('publishScoped', { pkgName: 'pkg-protected' }); + }); + + it('should have one published package', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.getByTestId('package-title').should('have.length', 1); + }); + + it('should navigate to page detail', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.wait('@pkgs'); + cy.wait(300); + cy.getByTestId('package-title').click(); + cy.wait('@sidebar'); + cy.wait('@readme'); + }); + + it('should have readme content', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.wait('@pkgs'); + cy.getByTestId('package-title').click(); + cy.wait('@sidebar'); + cy.wait('@readme'); + cy.get('.markdown-body').should('have.length', 1); + cy.contains('.markdown-body', /test/); + }); + + it('should click on dependencies tab', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.wait('@pkgs'); + cy.getByTestId('package-title').click(); + cy.wait('@sidebar'); + cy.wait('@readme'); + cy.getByTestId('dependencies-tab').click(); + cy.wait(100); + cy.getByTestId('dependencies').should('have.length', 1); + cy.getByTestId('verdaccio') + .children() + .invoke('text') + .should('match', /verdaccio/); + cy.screenshot(); + }); + + it('should click on versions tab', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.wait('@pkgs'); + cy.getByTestId('package-title').click(); + cy.wait('@sidebar'); + cy.wait('@readme'); + cy.getByTestId('versions-tab').click(); + cy.getByTestId('tag-latest').children().invoke('text').should('match', /1.0.6/); + cy.screenshot(); + }); + + it('should click on uplinks tab', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.wait('@pkgs'); + cy.getByTestId('package-title').click(); + cy.wait('@sidebar'); + cy.wait('@readme'); + cy.getByTestId('uplinks-tab').click(); + cy.getByTestId('no-uplinks').should('be.visible'); + cy.screenshot(); + }); +}); diff --git a/e2e/ui/cypress/e2e/signin.cy.ts b/e2e/ui/cypress/e2e/signin.cy.ts new file mode 100644 index 000000000..e6ed02836 --- /dev/null +++ b/e2e/ui/cypress/e2e/signin.cy.ts @@ -0,0 +1,31 @@ +describe('sign spec', () => { + let ctx: any = {}; + const credentials = { user: 'test', password: 'test' }; + beforeEach(async () => { + // @ts-expect-error + const registry = await cy.task('registry'); + ctx.url = registry.registryUrl; + cy.intercept('POST', '/-/verdaccio/sec/login').as('sign'); + }); + + it('should login user', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.getByTestId('logInDialogIcon').click(); + cy.wait(100); + cy.getByTestId('greetings-label').contains(credentials.user); + }); + + it('should logout an user', () => { + cy.visit(ctx.url); + cy.login(credentials.user, credentials.password); + cy.wait('@sign'); + cy.getByTestId('logInDialogIcon').click(); + cy.wait(100); + cy.getByTestId('logOutDialogIcon').click(); + cy.screenshot(); + cy.getByTestId('header--button-login').contains('Login'); + cy.screenshot(); + }); +}); diff --git a/e2e/ui/cypress/support/commands.ts b/e2e/ui/cypress/support/commands.ts new file mode 100644 index 000000000..acf3a7388 --- /dev/null +++ b/e2e/ui/cypress/support/commands.ts @@ -0,0 +1,37 @@ +/* eslint-disable no-undef */ +// / ; + +Cypress.Commands.add('getByTestId', (selector, ...args) => { + return cy.get(`[data-testid=${selector}]`, ...args); +}); + +// -- This is a parent command -- +Cypress.Commands.add('login', (user, password) => { + cy.getByTestId('header--button-login').click(); + cy.get('#login--dialog-username').type(user); + cy.get('#login--dialog-password').type(password); + cy.get('#login--dialog-button-submit').click(); +}); +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } diff --git a/e2e/ui/cypress/support/e2e.ts b/e2e/ui/cypress/support/e2e.ts new file mode 100644 index 000000000..b93ad2a89 --- /dev/null +++ b/e2e/ui/cypress/support/e2e.ts @@ -0,0 +1,19 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** +// Import commands.js using ES2015 syntax: +import './commands'; + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/e2e/ui/helper.ts b/e2e/ui/helper.ts deleted file mode 100644 index 77b217a31..000000000 --- a/e2e/ui/helper.ts +++ /dev/null @@ -1,36 +0,0 @@ -export const credentials = { user: 'test', password: 'test' }; - -export const clickElement = async function (page, selector, options = { delay: 100 }) { - const button = await page.$(selector); - await button.focus(); - await button.click(options); -}; - -export const evaluateSignIn = async function (page, matchText = 'Login') { - const text = await page.evaluate(() => { - return document.querySelector('button[data-testid="header--button-login"]')?.textContent; - }); - - expect(text).toMatch(matchText); -}; - -export const getPackages = async function (page) { - return await page.$$('.package-title'); -}; - -export const logIn = async function (page) { - await clickElement(page, 'div[data-testid="dialogContentLogin"]'); - const userInput = await page.$('#login--dialog-username'); - expect(userInput).not.toBeNull(); - const passInput = await page.$('#login--dialog-password'); - expect(passInput).not.toBeNull(); - await userInput.type(credentials.user, { delay: 100 }); - await passInput.type(credentials.password, { delay: 100 }); - await passInput.dispose(); - // click on log in - const loginButton = await page.$('#login--dialog-button-submit'); - expect(loginButton).toBeDefined(); - await loginButton.focus(); - await loginButton.click({ delay: 100 }); - await page.waitForTimeout(500); -}; diff --git a/e2e/ui/jest.config.js b/e2e/ui/jest.config.js deleted file mode 100644 index 80dffcf66..000000000 --- a/e2e/ui/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const config = require('../../jest/config'); - -module.exports = Object.assign({}, config, { - verbose: false, - collectCoverage: false, - globalSetup: './pre-setup.js', - globalTeardown: './teardown.js', -}); diff --git a/e2e/ui/package.json b/e2e/ui/package.json index e18be5393..29189f5ee 100644 --- a/e2e/ui/package.json +++ b/e2e/ui/package.json @@ -8,12 +8,10 @@ "@verdaccio/config": "workspace:6.0.0-6-next.48", "@verdaccio/test-helper": "workspace:2.0.0-6-next.5", "debug": "4.3.4", - "colorette": "2.0.19", - "lodash": "^4.17.21", - "puppeteer": "17.1.3", - "rimraf": "3.0.2" + "cypress": "10.10.0" }, "scripts": { - "test": "jest --runInBand" + "cypress:open": "cypress open", + "test": "cypress run" } } diff --git a/e2e/ui/publish.spec.js b/e2e/ui/publish.spec.js deleted file mode 100644 index f73bd781e..000000000 --- a/e2e/ui/publish.spec.js +++ /dev/null @@ -1,118 +0,0 @@ -const { join } = require('path'); -const { generatePackageMetadata } = require('@verdaccio/test-helper'); -const { fileUtils, HEADERS } = require('@verdaccio/core'); -const { parseConfigFile } = require('@verdaccio/config'); -const { Registry, ServerQuery } = require('verdaccio'); -const { getPackages } = require('./helper'); - -const protectedPackageMetadata = generatePackageMetadata('pkg-protected', '5.0.5'); -const scopedPackageMetadata = generatePackageMetadata('pkg-scoped', '1.0.6'); - -describe('publish package', () => { - let registry1; - let page; - beforeAll(async () => { - const configProtected = parseConfigFile(join(__dirname, './config/config.yaml')); - const registry1storage = await fileUtils.createTempStorageFolder('storage-1'); - const protectedRegistry = await Registry.fromConfigToPath({ - ...configProtected, - storage: registry1storage, - }); - registry1 = new Registry(protectedRegistry.configPath, { createUser: true }); - await registry1.init(); - - const query1 = new ServerQuery(registry1.getRegistryUrl()); - await query1.createUser('test', 'test'); - - page = await global.__BROWSER__.newPage(); - await page.goto(`http://0.0.0.0:${registry1.getPort()}`); - // eslint-disable-next-line no-console - page.on('console', (msg) => console.log('PAGE LOG:', msg.text())); - }); - - afterAll(async () => { - await page.close(); - registry1.stop(); - }); - - // this might be increased based on the delays included in all test - jest.setTimeout(20000); - - test('should publish a package', async () => { - const server = new ServerQuery(registry1.getRegistryUrl()); - await server.putPackage(scopedPackageMetadata.name, scopedPackageMetadata, { - [HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`, - }); - await page.waitForTimeout(1000); - await page.reload(); - await page.waitForTimeout(1000); - const packagesList = await getPackages(page); - expect(packagesList).toHaveLength(1); - }); - // - - test('should navigate to the package detail', async () => { - const packagesList = await getPackages(page); - const firstPackage = packagesList[0]; - await firstPackage.click({ delay: 200 }); - await page.waitForTimeout(1000); - const readmeText = await page.evaluate( - () => document.querySelector('.markdown-body').textContent - ); - - expect(readmeText).toMatch('test'); - }); - - test('should contains last sync information', async () => { - const versionList = await page.$$('.sidebar-info .detail-info'); - expect(versionList).toHaveLength(1); - }); - - test('should display dependencies tab', async () => { - const dependenciesTab = await page.$$('#dependencies-tab'); - expect(dependenciesTab).toHaveLength(1); - await dependenciesTab[0].click({ delay: 200 }); - await page.waitForTimeout(1000); - const tags = await page.$$('.dep-tag'); - const tag = tags[0]; - const label = await page.evaluate((el) => el.innerText, tag); - expect(label).toMatch('verdaccio@'); - }); - - test('should display version tab', async () => { - const versionsTab = await page.$$('#versions-tab'); - expect(versionsTab).toHaveLength(1); - await versionsTab[0].click({ delay: 200 }); - await page.waitForTimeout(1000); - const versionItems = await page.$$('.version-item'); - expect(versionItems).toHaveLength(2); - }); - - test('should display uplinks tab', async () => { - const upLinksTab = await page.$$('#uplinks-tab'); - expect(upLinksTab).toHaveLength(1); - await upLinksTab[0].click({ delay: 200 }); - await page.waitForTimeout(1000); - }); - - test('should display readme tab', async () => { - const readmeTab = await page.$$('#readme-tab'); - expect(readmeTab).toHaveLength(1); - await readmeTab[0].click({ delay: 200 }); - await page.waitForTimeout(1000); - }); - - test('should publish a second package', async () => { - await page.goto(`http://0.0.0.0:${registry1.getPort()}`); - await page.waitForTimeout(500); - const server = new ServerQuery(registry1.getRegistryUrl()); - await server.putPackage(protectedPackageMetadata.name, protectedPackageMetadata, { - [HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`, - }); - await page.waitForTimeout(500); - await page.reload(); - await page.waitForTimeout(500); - const packagesList = await getPackages(page); - expect(packagesList).toHaveLength(2); - }); -}); diff --git a/e2e/ui/sigin.spec.js b/e2e/ui/sigin.spec.js deleted file mode 100644 index b9b89e40f..000000000 --- a/e2e/ui/sigin.spec.js +++ /dev/null @@ -1,80 +0,0 @@ -const { join } = require('path'); -const { fileUtils } = require('@verdaccio/core'); -const { parseConfigFile } = require('@verdaccio/config'); -const { Registry, ServerQuery } = require('verdaccio'); -const { clickElement, logIn } = require('./helper'); - -describe('sign in user', () => { - let registry1; - let page; - beforeAll(async () => { - const configProtected = parseConfigFile(join(__dirname, './config/config.yaml')); - const registry1storage = await fileUtils.createTempStorageFolder('storage-1'); - const protectedRegistry = await Registry.fromConfigToPath({ - ...configProtected, - storage: registry1storage, - }); - registry1 = new Registry(protectedRegistry.configPath); - await registry1.init(); - - const query1 = new ServerQuery(registry1.getRegistryUrl()); - await query1.createUser('test', 'test'); - - page = await global.__BROWSER__.newPage(); - await page.goto(`http://0.0.0.0:${registry1.getPort()}`); - // eslint-disable-next-line no-console - page.on('console', (msg) => console.log('PAGE LOG:', msg.text())); - }); - - afterAll(async () => { - await page.close(); - registry1.stop(); - }); - - // this might be increased based on the delays included in all test - jest.setTimeout(20000); - - const evaluateSignIn = async function (matchText = 'Login') { - const text = await page.evaluate(() => { - return document.querySelector('button[data-testid="header--button-login"]').textContent; - }); - - expect(text).toMatch(matchText); - }; - - test('should match button Login to sign in', async () => { - await evaluateSignIn(); - }); - - test('should click on sign in button', async () => { - const signInButton = await page.$('button[data-testid="header--button-login"]'); - await signInButton.click(); - await page.waitForTimeout(1000); - const signInDialog = await page.$('#login--dialog'); - expect(signInDialog).not.toBeNull(); - const closeButton = await page.$('button[data-testid="close-login-dialog-button"]'); - await closeButton.click(); - await page.waitForTimeout(500); - }); - - test('should log in an user', async () => { - // we open the dialog - await logIn(page); - // verify if logged in - const accountButton = await page.$('#header--button-account'); - expect(accountButton).toBeDefined(); - // check whether user is logged - const buttonLogout = await page.$('#logOutDialogIcon'); - expect(buttonLogout).toBeDefined(); - }); - - test('should logout an user', async () => { - await page.waitForTimeout(10000); - // we assume the user is logged already - await clickElement(page, '#header--button-account', { delay: 500 }); - await page.waitForTimeout(1000); - await clickElement(page, '#logOutDialogIcon > span', { delay: 500 }); - await page.waitForTimeout(1000); - await evaluateSignIn(); - }); -}); diff --git a/e2e/ui/tsconfig.json b/e2e/ui/tsconfig.json new file mode 100644 index 000000000..29fefcd8a --- /dev/null +++ b/e2e/ui/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.reference.json", + "include": ["./cypress/**/*.ts", "./*.ts"], + "references": [ + { + "path": "../../packages/core/core" + }, + { + "path": "../../packages/verdaccio" + }, + { + "path": "../../packages/config" + }, + { + "path": "../../packages/tools/helpers" + } + ] +} diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Dependencies/Dependencies.tsx b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Dependencies/Dependencies.tsx index 23f47f2b8..17a1c4e27 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Dependencies/Dependencies.tsx +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Dependencies/Dependencies.tsx @@ -27,7 +27,7 @@ const DependencyBlock: React.FC = ({ title, dependencies } } return ( - + {`${title} (${deps.length})`} @@ -35,6 +35,7 @@ const DependencyBlock: React.FC = ({ title, dependencies } = ({ className, text }) => ( - +const NoItems: React.FC = ({ className, text, ...props }) => ( + // eslint-disable-next-line verdaccio/jsx-spread + {text} ); diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/UpLinks.tsx b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/UpLinks.tsx index 633541c41..40baad2af 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/UpLinks.tsx +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/UpLinks.tsx @@ -19,7 +19,7 @@ const UpLinks: React.FC = () => { const { _uplinks: uplinks, latest } = packageMeta; if (Object.keys(uplinks).length === 0) { - return ; + return ; } return ( diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/__snapshots__/UpLinks.test.tsx.snap b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/__snapshots__/UpLinks.test.tsx.snap index c72712846..0d2fa470c 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/__snapshots__/UpLinks.test.tsx.snap +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/UpLinks/__snapshots__/UpLinks.test.tsx.snap @@ -16,6 +16,7 @@ exports[` component should render the component when there is no upli
verdaccio has no uplinks.
@@ -33,6 +34,7 @@ exports[` component should render the component when there is no upli
verdaccio has no uplinks.
diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/Versions.tsx b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/Versions.tsx index 0431c729a..a3ccdfe9a 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/Versions.tsx +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/Versions.tsx @@ -1,7 +1,6 @@ import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { DIST_TAGS } from '../../../../../lib/constants'; import { DetailContext } from '../../context'; import VersionsHistoryList from './VersionsHistoryList'; import VersionsTagList from './VersionsTagList'; @@ -17,7 +16,7 @@ const Versions: React.FC = () => { return null; } - const { versions = {}, time = {}, [DIST_TAGS]: distTags = {} } = packageMeta; + const { versions = {}, time = {}, ['dist-tags']: distTags = {} } = packageMeta; return ( <> diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsHistoryList.tsx b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsHistoryList.tsx index 2bd9d796e..d51a0ee00 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsHistoryList.tsx +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsHistoryList.tsx @@ -21,7 +21,7 @@ const VersionsHistoryList: React.FC = ({ versions, packageName, time }) = {Object.keys(versions) .reverse() .map((version) => ( - + {version} diff --git a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsTagList.tsx b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsTagList.tsx index 6577e3c5b..0acdad189 100644 --- a/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsTagList.tsx +++ b/packages/plugins/ui-theme/src/pages/Version/DetailContainer/Versions/VersionsTagList.tsx @@ -19,7 +19,7 @@ const VersionsTagList: React.FC = ({ tags, packageName, time }) => ( return time[tags[a]] < time[tags[b]] ? 1 : time[tags[a]] > time[tags[b]] ? -1 : 0; }) .map((tag) => ( - + {tag} diff --git a/packages/plugins/ui-theme/src/pages/home/PackageList/Help/Help.tsx b/packages/plugins/ui-theme/src/pages/home/PackageList/Help/Help.tsx index aacb482f0..dcbc94844 100644 --- a/packages/plugins/ui-theme/src/pages/home/PackageList/Help/Help.tsx +++ b/packages/plugins/ui-theme/src/pages/home/PackageList/Help/Help.tsx @@ -25,7 +25,7 @@ const Help: React.FC = () => { const { t } = useTranslation(); return ( - + {t('help.title')} diff --git a/packages/plugins/ui-theme/src/pages/home/PackageList/Help/__snapshots__/Help.test.tsx.snap b/packages/plugins/ui-theme/src/pages/home/PackageList/Help/__snapshots__/Help.test.tsx.snap index 9028c8d8c..24178483d 100644 --- a/packages/plugins/ui-theme/src/pages/home/PackageList/Help/__snapshots__/Help.test.tsx.snap +++ b/packages/plugins/ui-theme/src/pages/home/PackageList/Help/__snapshots__/Help.test.tsx.snap @@ -284,6 +284,7 @@ exports[` component should load the component in default state 1`] = `
= ({ - {packageName} + + {packageName} + = 6'} + dependencies: + aws-sign2: 0.7.0 + aws4: 1.11.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.34 + performance-now: 2.1.0 + qs: 6.5.3 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + dev: true + + /@cypress/xvfb/1.2.4_supports-color@8.1.1: + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + dependencies: + debug: 3.2.7_supports-color@8.1.1 + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /@dianmora/contributors/5.0.0: resolution: {integrity: sha512-QhvpeVXjK3/q//9vxUtgK5y0chzIaT5c7aUJxR1mI86K0Kyy7rI9oWAiKyOmtO36H9xytODpq9ouoLZFdUfZBQ==} dependencies: @@ -9234,6 +9263,14 @@ packages: '@types/node': 17.0.21 dev: true + /@types/sinonjs__fake-timers/8.1.1: + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + dev: true + + /@types/sizzle/2.3.3: + resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + dev: true + /@types/sockjs/0.3.33: resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} dependencies: @@ -10079,6 +10116,10 @@ packages: engines: {node: '>=8'} dev: false + /arch/2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + dev: true + /archy/1.0.0: resolution: {integrity: sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=} @@ -10199,6 +10240,17 @@ packages: /asap/2.0.6: resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=} + /asn1/0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /assert-plus/1.0.0: + resolution: {integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=} + engines: {node: '>=0.8'} + dev: true + /assign-symbols/1.0.0: resolution: {integrity: sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=} engines: {node: '>=0.10.0'} @@ -10223,6 +10275,10 @@ packages: dependencies: lodash: 4.17.21 + /async/3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: true + /asynckit/0.4.0: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} @@ -10298,6 +10354,14 @@ packages: transitivePeerDependencies: - supports-color + /aws-sign2/0.7.0: + resolution: {integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=} + dev: true + + /aws4/1.11.0: + resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} + dev: true + /axe-core/4.4.3: resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} engines: {node: '>=4'} @@ -10668,6 +10732,12 @@ packages: /batch/0.6.1: resolution: {integrity: sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=} + /bcrypt-pbkdf/1.0.2: + resolution: {integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=} + dependencies: + tweetnacl: 0.14.5 + dev: true + /bcryptjs/2.4.3: resolution: {integrity: sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=} dev: false @@ -10709,6 +10779,10 @@ packages: readable-stream: 3.6.0 dev: true + /blob-util/2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + dev: true + /bluebird/3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true @@ -10975,6 +11049,11 @@ packages: normalize-url: 6.1.0 responselike: 2.0.0 + /cachedir/2.3.0: + resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} + engines: {node: '>=6'} + dev: true + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -11026,6 +11105,10 @@ packages: /caniuse-lite/1.0.30001410: resolution: {integrity: sha512-QoblBnuE+rG0lc3Ur9ltP5q47lbguipa/ncNMyyGuqPk44FxbScWAeEO+k5fSQ8WekdAK4mWqNs1rADDAiN5xQ==} + /caseless/0.12.0: + resolution: {integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=} + dev: true + /ccount/1.1.0: resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} @@ -11100,6 +11183,11 @@ packages: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true + /check-more-types/2.24.0: + resolution: {integrity: sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=} + engines: {node: '>= 0.8.0'} + dev: true + /cheerio-select/2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} dependencies: @@ -11433,6 +11521,11 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + /common-tags/1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + /commondir/1.0.1: resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} @@ -12286,10 +12379,67 @@ packages: array-find-index: 1.0.2 dev: true + /cypress/10.10.0: + resolution: {integrity: sha512-bU8r44x1NIYAUNNXt3CwJpLOVth7HUv2hUhYCxZmgZ1IugowDvuHNpevnoZRQx1KKOEisLvIJW+Xen5Pjn41pg==} + engines: {node: '>=12.0.0'} + hasBin: true + requiresBuild: true + dependencies: + '@cypress/request': 2.88.10 + '@cypress/xvfb': 1.2.4_supports-color@8.1.1 + '@types/node': 14.17.3 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.3 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.3.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.2 + commander: 5.1.0 + common-tags: 1.8.2 + dayjs: 1.11.5 + debug: 4.3.4_supports-color@8.1.1 + enquirer: 2.3.6 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1_supports-color@8.1.1 + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.13.5_enquirer@2.3.6 + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.6 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.3.7 + supports-color: 8.1.1 + tmp: 0.2.1 + untildify: 4.0.0 + yauzl: 2.10.0 + dev: true + /damerau-levenshtein/1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: false + /dashdash/1.14.1: + resolution: {integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + dev: true + /data-urls/3.0.0: resolution: {integrity: sha512-4AefxbTTdFtxDUdh0BuMBs2qJVL25Mow2zlcuuePegQwgD6GEmQao42LLEeksOui8nL4RcNEugIpFP7eRd33xg==} engines: {node: '>=12'} @@ -12375,6 +12525,18 @@ packages: ms: 2.1.3 supports-color: 6.1.0 + /debug/3.2.7_supports-color@8.1.1: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + dev: true + /debug/4.3.3: resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} engines: {node: '>=6.0'} @@ -12649,10 +12811,6 @@ packages: - supports-color dev: true - /devtools-protocol/0.0.1036444: - resolution: {integrity: sha512-0y4f/T8H9lsESV9kKP1HDUXgHxCdniFeJh6Erq+FbdOEvp/Ydp9t8kcAAM5gOd17pMrTDlFWntoHtzzeTUWKNw==} - dev: true - /dezalgo/1.0.3: resolution: {integrity: sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=} dependencies: @@ -12891,6 +13049,13 @@ packages: /eastasianwidth/0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + /ecc-jsbn/0.1.2: + resolution: {integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: true + /ecdsa-sig-formatter/1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: @@ -13470,6 +13635,15 @@ packages: eslint-rule-composer: 0.3.0 dev: false + /eslint-plugin-cypress/2.12.1_eslint@8.23.1: + resolution: {integrity: sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==} + peerDependencies: + eslint: '>= 3.2.1' + dependencies: + eslint: 8.23.1 + globals: 11.12.0 + dev: false + /eslint-plugin-import/2.26.0_a64a5b0f4abe31e3590db284fd772ccf: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} @@ -13757,6 +13931,10 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + /eventemitter2/6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + dev: true + /eventemitter3/4.0.6: resolution: {integrity: sha512-s3GJL04SQoM+gn2c14oyqxvZ3Pcq7cduSDqy3sBFXx6UPSUmgVYwQM9zwkTn9je0lrfg0gHEwR42pF3Q2dCQkQ==} @@ -13787,6 +13965,21 @@ packages: signal-exit: 3.0.7 strip-eof: 1.0.0 + /execa/4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + /execa/5.0.0: resolution: {integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==} engines: {node: '>=10'} @@ -13815,6 +14008,13 @@ packages: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + /executable/4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + dependencies: + pify: 2.3.0 + dev: true + /exit/0.1.2: resolution: {integrity: sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=} engines: {node: '>= 0.8.0'} @@ -13997,12 +14197,12 @@ packages: transitivePeerDependencies: - supports-color - /extract-zip/2.0.1: + /extract-zip/2.0.1_supports-color@8.1.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.4 + debug: 4.3.4_supports-color@8.1.1 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -14011,6 +14211,11 @@ packages: - supports-color dev: true + /extsprintf/1.3.0: + resolution: {integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=} + engines: {'0': node >=0.6.0} + dev: true + /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -14366,6 +14571,10 @@ packages: resolution: {integrity: sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=} engines: {node: '>=0.10.0'} + /forever-agent/0.6.1: + resolution: {integrity: sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=} + dev: true + /fork-ts-checker-webpack-plugin/4.1.6_a4613122169baab55b2b1552a44f40da: resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} engines: {node: '>=6.11.5', yarn: '>=1.0.0'} @@ -14425,6 +14634,15 @@ packages: typescript: 4.8.4 webpack: 5.74.0_esbuild@0.14.10 + /form-data/2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.34 + dev: true + /form-data/2.5.1: resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} engines: {node: '>= 0.12'} @@ -14488,10 +14706,6 @@ packages: webpack: 5.74.0_webpack-cli@4.7.2 dev: true - /fs-constants/1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true - /fs-extra/10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -14638,6 +14852,18 @@ packages: resolution: {integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=} engines: {node: '>=0.10.0'} + /getos/3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + dependencies: + async: 3.2.4 + dev: true + + /getpass/0.1.7: + resolution: {integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=} + dependencies: + assert-plus: 1.0.0 + dev: true + /github-markdown-css/4.0.0: resolution: {integrity: sha512-mH0bcIKv4XAN0mQVokfTdKo2OD5K8WJE9+lbMdM32/q0Ie5tXgVN/2o+zvToRMxSTUuiTRcLg5hzkFfOyBYreg==} dev: true @@ -15299,6 +15525,15 @@ packages: transitivePeerDependencies: - debug + /http-signature/1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.17.0 + dev: true + /http-status-codes/2.2.0: resolution: {integrity: sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==} @@ -15332,6 +15567,11 @@ packages: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true + /human-signals/1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + dev: true + /human-signals/2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -15971,6 +16211,10 @@ packages: resolution: {integrity: sha1-TkMekrEalzFjaqH5yNHMvP2reN8=} engines: {node: '>=0.10.0'} + /isstream/0.1.2: + resolution: {integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=} + dev: true + /istanbul-lib-coverage/3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} @@ -16568,6 +16812,10 @@ packages: dependencies: argparse: 2.0.1 + /jsbn/0.1.1: + resolution: {integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM=} + dev: true + /jsdom/17.0.0: resolution: {integrity: sha512-MUq4XdqwtNurZDVeKScENMPHnkgmdIvMzZ1r1NSwHkDuaqI6BouPjr+17COo4/19oLNnmdpFDPOHVpgIZmZ+VA==} engines: {node: '>=12'} @@ -16677,6 +16925,10 @@ packages: /json-schema-traverse/1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + /json-schema/0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=} @@ -16752,6 +17004,16 @@ packages: ms: 2.1.3 semver: 5.7.1 + /jsprim/2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: true + /jss-plugin-camel-case/10.9.2: resolution: {integrity: sha512-wgBPlL3WS0WDJ1lPJcgjux/SHnDuu7opmgQKSraKs4z8dCCyYMx9IDPFKBXQ8Q5dVYij1FFV0WdxyhuOOAXuTg==} dependencies: @@ -16915,6 +17177,11 @@ packages: dependencies: package-json: 6.5.0 + /lazy-ass/1.6.0: + resolution: {integrity: sha1-eZllXoZGwX8In90YfRUNMyTVRRM=} + engines: {node: '> 0.8'} + dev: true + /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -18024,10 +18291,6 @@ packages: engines: {node: '>= 8.0.0'} dev: true - /mkdirp-classic/0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true - /mkdirp/0.5.5: resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} hasBin: true @@ -18986,6 +19249,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /ospath/1.2.2: + resolution: {integrity: sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=} + dev: true + /outdent/0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} dev: true @@ -19238,6 +19505,10 @@ packages: resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=} dev: true + /performance-now/2.1.0: + resolution: {integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=} + dev: true + /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -20310,8 +20581,8 @@ packages: forwarded: 0.2.0 ipaddr.js: 1.9.1 - /proxy-from-env/1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + /proxy-from-env/1.0.0: + resolution: {integrity: sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=} dev: true /prr/1.0.1: @@ -20350,29 +20621,6 @@ packages: dependencies: escape-goat: 2.1.1 - /puppeteer/17.1.3: - resolution: {integrity: sha512-tVtvNSOOqlq75rUgwLeDAEQoLIiBqmRg0/zedpI6fuqIocIkuxG23A7FIl1oVSkuSMMLgcOP5kVhNETmsmjvPw==} - engines: {node: '>=14.1.0'} - requiresBuild: true - dependencies: - cross-fetch: 3.1.5 - debug: 4.3.4 - devtools-protocol: 0.0.1036444 - extract-zip: 2.0.1 - https-proxy-agent: 5.0.1 - progress: 2.0.3 - proxy-from-env: 1.1.0 - rimraf: 3.0.2 - tar-fs: 2.1.1 - unbzip2-stream: 1.4.3 - ws: 8.8.1 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - /pure-color/1.3.0: resolution: {integrity: sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=} @@ -20387,6 +20635,11 @@ packages: dependencies: side-channel: 1.0.4 + /qs/6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} + dev: true + /qs/6.7.0: resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==} engines: {node: '>=0.6'} @@ -21232,6 +21485,12 @@ packages: resolution: {integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc=} engines: {node: '>=0.10'} + /request-progress/3.0.0: + resolution: {integrity: sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=} + dependencies: + throttleit: 1.0.0 + dev: true + /require-directory/2.1.1: resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} engines: {node: '>=0.10.0'} @@ -22135,6 +22394,22 @@ packages: /sprintf-js/1.0.3: resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} + /sshpk/1.17.0: + resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: true + /stable/0.1.8: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} @@ -22636,26 +22911,6 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - /tar-fs/2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - dev: true - - /tar-stream/2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.0 - dev: true - /tar/4.4.19: resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} engines: {node: '>=4.5'} @@ -22854,6 +23109,10 @@ packages: dependencies: real-require: 0.2.0 + /throttleit/1.0.0: + resolution: {integrity: sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=} + dev: true + /through/2.3.8: resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=} @@ -22885,6 +23144,13 @@ packages: os-tmpdir: 1.0.2 dev: true + /tmp/0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + /tmpl/1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -22943,6 +23209,14 @@ packages: nopt: 1.0.10 dev: true + /tough-cookie/2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + dependencies: + psl: 1.8.0 + punycode: 2.1.1 + dev: true + /tough-cookie/4.0.0: resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==} engines: {node: '>=6'} @@ -23078,6 +23352,16 @@ packages: yargs: 17.3.1 dev: true + /tunnel-agent/0.6.0: + resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /tweetnacl/0.14.5: + resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=} + dev: true + /typanion/3.3.1: resolution: {integrity: sha512-VogBiMj3ZQuWaHkbhXwSgd9jXE4s7EMaaV7VSEiKTNYnKJs/bPjvcOGbD7rTM9aPqTABvgLVEZ+iFP6ab12HtQ==} dev: false @@ -23228,13 +23512,6 @@ packages: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - /unbzip2-stream/1.4.3: - resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} - dependencies: - buffer: 5.7.1 - through: 2.3.8 - dev: true - /undefsafe/2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} dev: true @@ -23447,6 +23724,11 @@ packages: has-value: 0.3.1 isobject: 3.0.1 + /untildify/4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + /upath/1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} @@ -23808,6 +24090,15 @@ packages: resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=} engines: {node: '>= 0.8'} + /verror/1.10.0: + resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + dev: true + /vfile-location/3.2.0: resolution: {integrity: sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==} @@ -24743,19 +25034,6 @@ packages: utf-8-validate: optional: true - /ws/8.8.1: - resolution: {integrity: sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - /xdg-basedir/4.0.0: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'}