feat: improved DX for unified-desktop-gui (#18099)

- Moves graphql-codegen config to the root, which will serve all packages needing it
- Adds gulpfile for coordinating scripts related to dev environment in launchpad app
- yarn dev from the root runs yarn gulp dev, which:
  Runs autobarrel for rolling up the @packages/graphql files
  Cleans the dist & cache for .vite
  Starts the a codegen watcher for Nexus
  Starts the graphql-codegen --watch & highlights output
  Starts vite servers for launchpad & app
  Starts electron watch.js
This commit is contained in:
Tim Griesser
2021-09-15 11:54:14 -04:00
committed by GitHub
parent 8bda0a9d02
commit a851d797a8
54 changed files with 1258 additions and 426 deletions

6
autobarrel.json Normal file
View File

@@ -0,0 +1,6 @@
{
"prefix": "/* eslint-disable padding-line-between-statements */",
"paths": [
"packages/graphql/src/**/*"
]
}

View File

@@ -389,6 +389,7 @@ commands:
type: string
steps:
- restore_cached_workspace
- run: yarn gulp graphqlCodegen
- run: yarn workspace @packages/launchpad cypress:run --browser <<parameters.browser>>
- store_test_results:
path: /tmp/cypress
@@ -1001,6 +1002,8 @@ jobs:
- run: yarn test-scripts
# make sure our snapshots are compared correctly
- run: yarn test-mocha-snapshot
# Get the codegen output
- run: yarn gulp buildProd
# make sure packages with TypeScript can be transpiled to JS
- run: yarn lerna run build-prod --stream
# run unit tests from each individual package

View File

@@ -397,6 +397,7 @@ module.exports = {
debug('opening Cypress')
require('./exec/open')
.start(util.parseOpts(opts))
.then(util.exit)
.catch(util.logErrorExit1)
})

View File

@@ -102,13 +102,13 @@ module.exports = {
const electronArgs = []
const node11WindowsFix = isPlatform('win32')
let startScriptPath
if (options.dev) {
executable = 'node'
// if we're in dev then reset
// the launch cmd to be 'npm run dev'
executable = 'node'
electronArgs.unshift(
path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'),
)
startScriptPath = path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'),
debug('in dev mode the args became %o', args)
}
@@ -141,9 +141,7 @@ module.exports = {
if (stdioOptions.env.ELECTRON_RUN_AS_NODE) {
// Since we are running electron as node, we need to add an entry point file.
const serverEntryPoint = path.join(state.getBinaryPkgPath(path.dirname(executable)), '..', 'index.js')
args = [serverEntryPoint, ...args]
startScriptPath = path.join(state.getBinaryPkgPath(path.dirname(executable)), '..', 'index.js')
} else {
// Start arguments with "--" so Electron knows these are OUR
// arguments and does not try to sanitize them. Otherwise on Windows
@@ -152,9 +150,23 @@ module.exports = {
args = [...electronArgs, '--', ...args]
}
debug('spawning Cypress with executable: %s', executable)
debug('spawn args %o %o', args, _.omit(stdioOptions, 'env'))
const child = cp.spawn(executable, args, stdioOptions)
let child
if (process.env.CYPRESS_INTERNAL_DEV_WATCH) {
debug('spawning Cypress as fork: %s', startScriptPath)
child = cp.fork(startScriptPath, args, stdioOptions)
process.on('message', (msg) => {
child.send(msg)
})
} else {
debug('spawning Cypress with executable: %s', executable)
if (startScriptPath) {
args.unshift(startScriptPath)
}
child = cp.spawn(executable, args, stdioOptions)
}
function resolveOn (event) {
return function (code, signal) {

38
graphql-codegen.yml Normal file
View File

@@ -0,0 +1,38 @@
overwrite: true
schema: './packages/graphql/schema.graphql'
generates:
'./packages/app/src/generated/graphql.ts':
documents: './packages/app/src/**/*.vue'
config:
immutableTypes: true
useTypeImports: true
preResolveTypes: true
onlyOperationTypes: true
avoidOptionals: true
enumsAsTypes: true
plugins:
- add:
content: '/* eslint-disable */'
- 'typescript':
- 'typescript-operations'
- 'typed-document-node'
'./packages/launchpad/src/generated/graphql.ts':
documents: './packages/launchpad/src/**/*.vue'
config:
immutableTypes: true
useTypeImports: true
preResolveTypes: true
onlyOperationTypes: true
avoidOptionals: true
enumsAsTypes: true
plugins:
- add:
content: '/* eslint-disable */'
- 'typescript':
- 'typescript-operations'
- 'typed-document-node'
'./packages/graphql/src/testing/testUnionType.ts':
plugins:
- add:
content: '/* eslint-disable */'
- 'packages/graphql/script/codegen-mount.js'

2
gulpfile.js Normal file
View File

@@ -0,0 +1,2 @@
require('@packages/ts/register')
require('./scripts/gulp/gulpfile')

View File

@@ -4,6 +4,7 @@
"description": "Cypress.io end to end testing tool",
"private": true,
"scripts": {
"prebinary-build": "yarn gulp buildProd",
"binary-build": "node ./scripts/binary.js build",
"binary-deploy": "node ./scripts/binary.js deploy",
"binary-deploy-linux": "./scripts/build-linux-binary.sh",
@@ -13,6 +14,7 @@
"binary-upload": "node ./scripts/binary.js upload",
"binary-zip": "node ./scripts/binary.js zip",
"build": "lerna run build --stream --no-bail --ignore create-cypress-tests && lerna run build --stream --scope create-cypress-tests",
"prebuild-prod": "yarn gulp buildProd",
"build-prod": "lerna run build-prod --stream --ignore create-cypress-tests && lerna run build-prod --stream --scope create-cypress-tests",
"bump": "node ./scripts/binary.js bump",
"check-node-version": "node scripts/check-node-version.js",
@@ -29,14 +31,14 @@
"precypress:run:debug": "yarn ensure-deps",
"cypress:run:debug": "node ./scripts/debug.js cypress:run",
"cypress:verify": "cypress verify --dev",
"dev": "node ./scripts/start.js",
"dev:watch": "node ./scripts/watch.js",
"dev": "yarn gulp dev",
"gulp:debug": "node --inspect-brk ./node_modules/.bin/gulp",
"dev-debug": "node ./scripts/debug.js dev",
"docker": "./scripts/run-docker-local.sh",
"effective:circle:config": "circleci config process circle.yml | sed /^#/d",
"ensure-deps": "./scripts/ensure-dependencies.sh",
"get-next-version": "node scripts/get-next-version.js",
"postinstall": "yarn-deduplicate --strategy=highest && patch-package && ./scripts/run-if-not-ci.sh yarn build",
"postinstall": "yarn-deduplicate --strategy=highest && patch-package && yarn gulp postinstall && ./scripts/run-if-not-ci.sh yarn build",
"jscodeshift": "jscodeshift -t ./node_modules/js-codemod/transforms/arrow-function-arguments.js",
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json .",
"lint-changed": "lint-changed",
@@ -81,6 +83,12 @@
"@cypress/request": "2.88.6",
"@cypress/request-promise": "4.2.6",
"@fellow/eslint-plugin-coffee": "0.4.13",
"@graphql-codegen/add": "^2.0.2",
"@graphql-codegen/cli": "^1.21.6",
"@graphql-codegen/plugin-helpers": "^2.1.1",
"@graphql-codegen/typed-document-node": "^1.18.9",
"@graphql-codegen/typescript": "^1.22.4",
"@graphql-codegen/typescript-operations": "^1.18.3",
"@percy/cli": "1.0.0-beta.48",
"@percy/cypress": "^3.1.0",
"@semantic-release/changelog": "5.0.1",
@@ -89,10 +97,13 @@
"@types/chai-enzyme": "0.6.7",
"@types/classnames": "2.2.9",
"@types/debug": "4.1.5",
"@types/detect-port": "^1.3.1",
"@types/enzyme-adapter-react-16": "1.0.5",
"@types/execa": "0.9.0",
"@types/fs-extra": "^8.0.1",
"@types/getenv": "^1.0.0",
"@types/glob": "7.1.1",
"@types/gulp": "^4.0.9",
"@types/lodash": "4.14.168",
"@types/markdown-it": "0.0.9",
"@types/mini-css-extract-plugin": "1.4.2",
@@ -104,11 +115,13 @@
"@types/react-dom": "16.9.8",
"@types/request-promise": "4.1.45",
"@types/sinon-chai": "3.2.3",
"@types/through2": "^2.0.36",
"@typescript-eslint/eslint-plugin": "4.18.0",
"@typescript-eslint/parser": "4.18.0",
"ansi-styles": "3.2.1",
"arg": "4.1.2",
"ascii-table": "0.0.9",
"autobarrel": "^1.1.0",
"aws-sdk": "2.447.0",
"babel-eslint": "10.1.0",
"bluebird": "3.5.3",
@@ -123,6 +136,7 @@
"conventional-recommended-bump": "6.1.0",
"debug": "4.3.2",
"del": "3.0.0",
"detect-port": "^1.3.0",
"electron-builder": "22.9.1",
"electron-notarize": "1.0.0",
"enzyme-adapter-react-16": "1.12.1",
@@ -137,6 +151,7 @@
"filesize": "4.1.2",
"find-package-json": "1.2.0",
"fs-extra": "8.1.0",
"getenv": "^1.0.0",
"gift": "0.10.2",
"glob": "7.1.6",
"globby": "10.0.1",
@@ -170,6 +185,7 @@
"mocha-multi-reporters": "1.1.7",
"mock-fs": "4.9.0",
"odiff-bin": "2.1.0",
"p-defer": "^3.0.0",
"parse-github-repo-url": "1.4.1",
"patch-package": "6.2.2",
"plist": "3.0.1",
@@ -193,6 +209,7 @@
"term-to-html": "1.2.0",
"terminal-banner": "1.1.0",
"through": "2.3.8",
"through2": "^4.0.2",
"ts-node": "8.3.0",
"typescript": "^4.2.3",
"yarn-deduplicate": "3.1.0"

View File

@@ -1,23 +0,0 @@
overwrite: true
schema: '../graphql/schema.graphql'
generates:
src/generated/graphql.ts:
documents: 'src/**/*.vue'
config:
immutableTypes: true
useTypeImports: true
preResolveTypes: true
onlyOperationTypes: true
avoidOptionals: true
enumsAsTypes: true
plugins:
- add:
content: '/* eslint-disable */'
- 'typescript'
- 'typescript-operations'
- 'typed-document-node'
../graphql/src/testing/testUnionType.ts:
plugins:
- add:
content: '/* eslint-disable */'
- 'script/codegen-mount.js'

View File

@@ -3,29 +3,21 @@
"version": "0.0.0-development",
"private": true,
"scripts": {
"prebuild": "yarn codegen",
"build": "vite build",
"types": "vue-tsc --noEmit",
"build-prod": "cross-env NODE_ENV=production yarn build",
"build-prod": "cross-env NODE_ENV=production vite build",
"clean": "rm -rf dist && rm -rf ./node_modules/.vite && echo 'cleaned'",
"clean-deps": "rm -rf node_modules",
"test": "echo ok",
"test": "echo 'ok'",
"cypress:launch": "cross-env TZ=America/New_York node ../../scripts/cypress open --project ${PWD}",
"cypress:open": "cross-env TZ=America/New_York node ../../scripts/cypress open-ct --project ${PWD}",
"cypress:run": "cross-env TZ=America/New_York node ../../scripts/cypress run-ct --project ${PWD}",
"dev": "NODE_ENV=development LAUNCHPAD=1 node ../../scripts/cypress open",
"postinstall": "yarn codegen && echo '@packages/launchpad needs: yarn build'",
"start": "vite --port 3333 --base /__vite__/",
"watch": "concurrently \"yarn start\" \"yarn codegen --watch\"",
"codegen": "graphql-codegen --config ${PWD}/graphql-codegen.yml"
"dev": "yarn gulp dev --project ${PWD}",
"start": "echo \"run 'yarn dev' from the root\" && exit 1",
"watch": "echo \"run 'yarn dev' from the root\" && exit 1"
},
"dependencies": {},
"devDependencies": {
"@cypress/vue": "0.0.0-development",
"@graphql-codegen/add": "^2.0.2",
"@graphql-codegen/cli": "^1.21.6",
"@graphql-codegen/typed-document-node": "^1.18.9",
"@graphql-codegen/typescript": "^1.22.4",
"@graphql-codegen/typescript-operations": "^1.18.3",
"@graphql-typed-document-node/core": "^3.1.0",
"@headlessui/vue": "1.4.0",
"@iconify/json": "1.1.368",
@@ -37,9 +29,6 @@
"@urql/vue": "0.4.3",
"@vitejs/plugin-vue": "1.2.4",
"@vitejs/plugin-vue-jsx": "1.1.6",
"@vue/compiler-core": "3.2.6",
"@vue/compiler-dom": "3.2.6",
"@vue/compiler-sfc": "3.2.6",
"@vueuse/core": "5.2.0",
"bluebird": "3.5.3",
"classnames": "2.3.1",
@@ -67,8 +56,6 @@
"files": [
"dist",
"lib",
"script",
"graphql-codegen.yml",
"src"
]
}

View File

@@ -156,7 +156,7 @@ module.exports = {
return process.exit(code)
})
if (process.argv.includes('--devWatch')) {
if (process.env.CYPRESS_INTERNAL_DEV_WATCH) {
spawned.on('exit', () => {
process.exit(0)
})

View File

@@ -5,9 +5,8 @@
"main": "index.js",
"browser": "src/index.ts",
"scripts": {
"build": "node script/build-schema.js",
"types": "tsc --noEmit",
"build-prod": "yarn build && tsc",
"build-prod": "yarn gulp nexusCodegen && tsc",
"clean-deps": "rm -rf node_modules",
"clean": "rm -f ./src/*.js ./src/**/*.js ./src/**/**/*.js ./test/**/*.js || echo 'cleaned'",
"postinstall": "echo '@packages/graphql needs: yarn build'",

View File

@@ -1,8 +0,0 @@
process.env.CYPRESS_INTERNAL_ENV = 'development'
process.env.GRAPHQL_CODEGEN = 'true'
process.env.GRAPHQL_CODEGEN_EXIT = 'true'
// TODO: we should be upgrading ts-node or moving to Thorsten's work soon
// and then this can be removed
process.env.TS_NODE_CACHE = 'false'
require('@packages/ts/register')
require('../src/schema')

View File

@@ -0,0 +1,4 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './BaseActions'

View File

@@ -1,7 +1,7 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './browserConstants'
export * from './wizardConstants'
export * from './projectConstants'
export * from './runConstants'
export * from './wizardConstants'

View File

@@ -0,0 +1,4 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './BaseContext'

View File

@@ -1 +1,5 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './BrowserContract'
export * from './ProjectContract'

View File

@@ -1,27 +1,20 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './App'
export * from './Browser'
export * from './DashboardProject'
export * from './Project'
export * from './Mutation'
export * from './NavigationMenu'
export * from './LocalProject'
export * from './ResolvedConfig'
export * from './Mutation'
export * from './NavigationItem'
export * from './NavigationMenu'
export * from './Project'
export * from './Query'
export * from './ResolvedConfig'
export * from './TestingTypeInfo'
export * from './Viewer'
export * from './Wizard'
export * from './WizardBundler'
export * from './WizardFrontendFramework'
export * from './WizardNpmPackage'
export * from './run/'

View File

@@ -1,3 +1,5 @@
export * from './Run'
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './Run'
export * from './RunCommit'

View File

@@ -0,0 +1,4 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './nxs.gen'

View File

@@ -7,21 +7,21 @@
import type { BaseContext } from "./../context/BaseContext"
import type { App } from "./../entities/App"
import type { Browser } from "./../entities/Browser"
import type { DashboardProject } from "./../entities/DashboardProject"
import type { Project } from "./../entities/Project"
import type { NavigationMenu } from "./../entities/NavigationMenu"
import type { LocalProject } from "./../entities/LocalProject"
import type { ResolvedOptionBase, ResolvedStringOption, ResolvedStringListOption, ResolvedNumberOption, ResolvedBooleanOption, ResolvedJsonOption, ResolvedConfig } from "./../entities/ResolvedConfig"
import type { NavigationItem } from "./../entities/NavigationItem"
import type { NavigationMenu } from "./../entities/NavigationMenu"
import type { Project } from "./../entities/Project"
import type { Query } from "./../entities/Query"
import type { ResolvedOptionBase, ResolvedStringOption, ResolvedStringListOption, ResolvedNumberOption, ResolvedBooleanOption, ResolvedJsonOption, ResolvedConfig } from "./../entities/ResolvedConfig"
import type { TestingTypeInfo } from "./../entities/TestingTypeInfo"
import type { Viewer } from "./../entities/Viewer"
import type { Wizard } from "./../entities/Wizard"
import type { WizardBundler } from "./../entities/WizardBundler"
import type { WizardFrontendFramework } from "./../entities/WizardFrontendFramework"
import type { WizardNpmPackage } from "./../entities/WizardNpmPackage"
import type { Browser } from "./../entities/Browser"
import type { RunGroup } from "./../entities/run/Run"
import type { NavigationItem } from "./../entities/NavigationItem"
import type { RunCommit } from "./../entities/run/RunCommit"
import type { core } from "nexus"
declare global {

View File

@@ -16,12 +16,12 @@ const dirname = typeof __dirname !== 'undefined' ? __dirname : ''
// for vite
process.cwd ??= () => ''
const isCodegen = Boolean(process.env.GRAPHQL_CODEGEN)
const isCodegen = Boolean(process.env.CYPRESS_INTERNAL_NEXUS_CODEGEN)
export const graphqlSchema = makeSchema({
types: [entities, constants, customScalars, dirname ? null : testingTypes],
shouldGenerateArtifacts: isCodegen,
shouldExitAfterGenerateArtifacts: Boolean(process.env.GRAPHQL_CODEGEN_EXIT),
shouldExitAfterGenerateArtifacts: isCodegen,
// for vite
outputs: isCodegen ? {
typegen: path.join(dirname, 'gen/nxs.gen.ts'),

View File

@@ -0,0 +1,5 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './ProjectBaseTest'
export * from './testUnionType'

View File

@@ -0,0 +1,4 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './wizardGetConfigCode'

View File

@@ -0,0 +1,122 @@
export const longBrowsersList = [
{
"name": "chrome",
"displayName": "Chrome",
"family": "chromium",
"channel": "stable",
"version": "78.0.3904.108",
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"majorVersion": "78"
},
{
"name": "chrome",
"displayName": "Chrome",
"family": "chromium",
"channel": "stable",
"version": "88.0.3904.00",
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"majorVersion": "88"
},
{
"name": "chrome",
"displayName": "Canary",
"family": "chromium",
"channel": "canary",
"version": "80.0.3977.4",
"path": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
"majorVersion": "80"
},
{
"name": "chromium",
"displayName": "Chromium",
"family": "chromium",
"channel": "stable",
"version": "74.0.3729.0",
"path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
"majorVersion": "74"
},
{
"name": "chromium",
"displayName": "Chromium",
"family": "chromium",
"channel": "stable",
"version": "85.0.3729.0",
"path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
"majorVersion": "85"
},
{
"name": "edge",
"displayName": "Edge Beta",
"family": "chromium",
"channel": "beta",
"version": "79.0.309.71",
"path": "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
"majorVersion": "79"
},
{
"name": "edge",
"displayName": "Edge Canary",
"family": "chromium",
"channel": "canary",
"version": "79.0.309.71",
"path": "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary",
"majorVersion": "79"
},
{
"name": "edge",
"displayName": "Edge Dev",
"family": "chromium",
"channel": "dev",
"version": "80.0.309.71",
"path": "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
"majorVersion": "79"
},
{
"name": "electron",
"displayName": "Electron",
"family": "chromium",
"channel": "stable",
"version": "73.0.3683.121",
"path": "",
"majorVersion": "73",
"info": "Info about electron browser"
},
{
"name": "firefox",
"displayName": "Firefox",
"family": "firefox",
"channel": "stable",
"version": "69.0.1",
"path": "/Applications/Firefox/Contents/MacOS/Firefox",
"majorVersion": "69",
"unsupportedVersion": true
},
{
"name": "firefox",
"displayName": "Firefox",
"family": "firefox",
"channel": "stable",
"version": "75.0.1",
"path": "/Applications/Firefox/Contents/MacOS/Firefox",
"majorVersion": "75",
"unsupportedVersion": true
},
{
"name": "firefox",
"displayName": "Firefox Developer Edition",
"channel": "dev",
"family": "firefox",
"version": "69.0.2",
"path": "/Applications/Firefox Developer/Contents/MacOS/Firefox Developer",
"majorVersion": "69"
},
{
"name": "firefox",
"displayName": "Firefox Nightly",
"channel": "beta",
"family": "firefox",
"version": "69.0.3",
"path": "/Applications/Firefox Nightly/Contents/MacOS/Firefox Nightly",
"majorVersion": "69"
}
] as const

View File

@@ -1,122 +0,0 @@
[
{
"name": "chrome",
"displayName": "Chrome",
"family": "chromium",
"channel": "stable",
"version": "78.0.3904.108",
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"majorVersion": "78"
},
{
"name": "chrome",
"displayName": "Chrome",
"family": "chromium",
"channel": "stable",
"version": "88.0.3904.00",
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"majorVersion": "88"
},
{
"name": "chrome",
"displayName": "Canary",
"family": "chromium",
"channel": "canary",
"version": "80.0.3977.4",
"path": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
"majorVersion": "80"
},
{
"name": "chromium",
"displayName": "Chromium",
"family": "chromium",
"channel": "stable",
"version": "74.0.3729.0",
"path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
"majorVersion": "74"
},
{
"name": "chromium",
"displayName": "Chromium",
"family": "chromium",
"channel": "stable",
"version": "85.0.3729.0",
"path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
"majorVersion": "85"
},
{
"name": "edge",
"displayName": "Edge Beta",
"family": "chromium",
"channel": "beta",
"version": "79.0.309.71",
"path": "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
"majorVersion": "79"
},
{
"name": "edge",
"displayName": "Edge Canary",
"family": "chromium",
"channel": "canary",
"version": "79.0.309.71",
"path": "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary",
"majorVersion": "79"
},
{
"name": "edge",
"displayName": "Edge Dev",
"family": "chromium",
"channel": "dev",
"version": "80.0.309.71",
"path": "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
"majorVersion": "79"
},
{
"name": "electron",
"displayName": "Electron",
"family": "chromium",
"channel": "stable",
"version": "73.0.3683.121",
"path": "",
"majorVersion": "73",
"info": "Info about electron browser"
},
{
"name": "firefox",
"displayName": "Firefox",
"family": "firefox",
"channel": "stable",
"version": "69.0.1",
"path": "/Applications/Firefox/Contents/MacOS/Firefox",
"majorVersion": "69",
"unsupportedVersion": true
},
{
"name": "firefox",
"displayName": "Firefox",
"family": "firefox",
"channel": "stable",
"version": "75.0.1",
"path": "/Applications/Firefox/Contents/MacOS/Firefox",
"majorVersion": "75",
"unsupportedVersion": true
},
{
"name": "firefox",
"displayName": "Firefox Developer Edition",
"channel": "dev",
"family": "firefox",
"version": "69.0.2",
"path": "/Applications/Firefox Developer/Contents/MacOS/Firefox Developer",
"majorVersion": "69"
},
{
"name": "firefox",
"displayName": "Firefox Nightly",
"channel": "beta",
"family": "firefox",
"version": "69.0.3",
"path": "/Applications/Firefox Nightly/Contents/MacOS/Firefox Nightly",
"majorVersion": "69"
}
]

View File

@@ -1,23 +0,0 @@
overwrite: true
schema: '../graphql/schema.graphql'
generates:
src/generated/graphql.ts:
documents: 'src/**/*.vue'
config:
immutableTypes: true
useTypeImports: true
preResolveTypes: true
onlyOperationTypes: true
avoidOptionals: true
enumsAsTypes: true
plugins:
- add:
content: '/* eslint-disable */'
- 'typescript'
- 'typescript-operations'
- 'typed-document-node'
../graphql/src/testing/testUnionType.ts:
plugins:
- add:
content: '/* eslint-disable */'
- 'script/codegen-mount.js'

View File

@@ -3,29 +3,21 @@
"version": "0.0.0-development",
"private": true,
"scripts": {
"prebuild": "yarn codegen",
"build": "vite build",
"types": "vue-tsc --noEmit",
"build-prod": "cross-env NODE_ENV=production yarn build",
"build-prod": "cross-env NODE_ENV=production vite build",
"clean": "rm -rf dist && rm -rf ./node_modules/.vite && echo 'cleaned'",
"clean-deps": "rm -rf node_modules",
"test": "yarn cypress:run && yarn types",
"cypress:launch": "cross-env TZ=America/New_York node ../../scripts/cypress open --project ${PWD}",
"cypress:open": "cross-env TZ=America/New_York node ../../scripts/cypress open-ct --project ${PWD}",
"cypress:run": "cross-env TZ=America/New_York node ../../scripts/cypress run-ct --project ${PWD}",
"dev": "NODE_ENV=development LAUNCHPAD=1 node ../../scripts/cypress open",
"postinstall": "yarn codegen && echo '@packages/launchpad needs: yarn build'",
"start": "vite --port 3001",
"watch": "concurrently \"yarn start\" \"yarn codegen --watch\"",
"codegen": "graphql-codegen --config ${PWD}/graphql-codegen.yml"
"dev": "yarn gulp dev --project ${PWD}",
"start": "echo 'run yarn dev from the root' && exit 1",
"watch": "echo 'run yarn dev from the root' && exit 1"
},
"dependencies": {},
"devDependencies": {
"@cypress/vue": "0.0.0-development",
"@graphql-codegen/add": "^2.0.2",
"@graphql-codegen/cli": "^1.21.6",
"@graphql-codegen/typed-document-node": "^1.18.9",
"@graphql-codegen/typescript": "^1.22.4",
"@graphql-codegen/typescript-operations": "^1.18.3",
"@graphql-typed-document-node/core": "^3.1.0",
"@headlessui/vue": "1.4.0",
"@iconify/json": "1.1.368",
@@ -68,7 +60,6 @@
"dist",
"lib",
"script",
"graphql-codegen.yml",
"src"
]
}

View File

@@ -1,67 +0,0 @@
import type { CodegenPlugin } from '@graphql-codegen/plugin-helpers'
import { isInterfaceType, isObjectType } from 'graphql'
import path from 'path'
const plugin: CodegenPlugin<any> = {
plugin: (schema, documents, config, info) => {
const typesMap = schema.getTypeMap()
let typeMap: string[] = []
let objects: string[] = []
for (const [typeName, type] of Object.entries(typesMap)) {
if (!typeName.startsWith('__') && isObjectType(type) || isInterfaceType(type)) {
typeMap.push(` ${typeName}: NexusGenObjects['${typeName}'],`)
if (isObjectType(type)) {
objects.push(typeName)
}
}
}
return [
`// Generated by ${path.basename(__filename)}, do not edit directly`,
`import type { NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen'`,
`export interface TestSourceTypeLookup {`,
typeMap.join('\n'),
`}`,
`
import { list, nonNull, queryField, unionType } from 'nexus'
export const testUnionType = unionType({
name: 'TestUnion',
definition (t) {
// !!! Generated by ${path.basename(__filename)}, do not edit directly !!!
t.members(
${objects.map((o) => `'${o}'`).join(',\n ')}
)
// !!! Generated by ${path.basename(__filename)}, do not edit directly !!!
},
resolveType (c) {
// @ts-ignore
return c.__typename ?? c.constructor.name
},
})
// !!! Generated by ${path.basename(__filename)}, do not edit directly !!!
export const testFragmentMember = queryField('testFragmentMember', {
description: 'Provides a fragment target for testing',
type: nonNull(testUnionType),
resolve: (source) => {
return source
}
})
// !!! Generated by ${path.basename(__filename)}, do not edit directly !!!
export const testFragmentMemberList = queryField('testFragmentMemberList', {
description: 'Provides a fragment target list for testing',
type: list(nonNull(testUnionType)),
resolve: (source) => {
return source
}
})
`,
].join('\n')
},
}
export default plugin

View File

@@ -1,2 +0,0 @@
require('@packages/ts/register')
module.exports = require('./codegen-mount-ts').default

View File

@@ -10,7 +10,7 @@ describe('<Button />', () => {
<Button size="lg">Primary with text</Button>
<Button variant="outline" size="sm" prefixIcon={IconCoffee}>Primary with text</Button>
<Button variant="outline">Outline with text</Button>
<Button variant="underline">An Underlined button</Button>
{/* <Button variant="underline">An Underlined button</Button> */}
</div>
))
})

View File

@@ -1,15 +1,15 @@
<template>
<WizardLayout no-container :canNavigateForward="false" :showNext="false" #={backFn}>
<div v-if="query.fetching.value">
<div v-if="!query.data.value">
Loading browsers...
</div>
<OpenBrowserList
v-else
variant=""
:gql="query.data.value.app"
@navigated-back="backFn"
@launch="launch"
/>
<OpenBrowserList
v-else
variant=""
:gql="query.data.value.app"
@navigated-back="backFn"
@launch="launch"
/>
</WizardLayout>
</template>
@@ -18,7 +18,6 @@ import { useMutation, gql, useQuery } from "@urql/vue";
import OpenBrowserList from "./OpenBrowserList.vue"
import WizardLayout from "./WizardLayout.vue";
import { OpenBrowserDocument, LaunchOpenProjectDocument } from "../generated/graphql"
import { ref } from "vue"
gql`
query OpenBrowser {

View File

@@ -1,6 +1,6 @@
import { OpenBrowserListFragmentDoc } from '../generated/graphql'
import OpenBrowserList from './OpenBrowserList.vue'
import longBrowserList from '../../cypress/fixtures/browsers/long-list.json'
import { longBrowsersList } from '../../cypress/fixtures/browsers/long-browsers-list'
const launchButtonSelector = 'button[data-testid=launch-button]'
@@ -9,14 +9,14 @@ describe('<OpenBrowserList />', () => {
cy.viewport(1000, 750)
cy.mountFragment(OpenBrowserListFragmentDoc, {
type: (ctx) => {
ctx.app.setBrowsers(longBrowserList)
ctx.app.setBrowsers(Array.from(longBrowsersList))
return ctx.app
},
render: (gqlVal) => <div class="resize overflow-auto border-current border-1"><OpenBrowserList gql={gqlVal} /></div>,
})
longBrowserList.forEach((browser) => {
longBrowsersList.forEach((browser) => {
cy.contains('label', browser.displayName).should('be.visible')
})

View File

@@ -77,17 +77,19 @@ import edgeDevIcon from "../../../../node_modules/browser-logos/src/edge-dev/edg
import firefoxNightlyIcon from "../../../../node_modules/browser-logos/src/firefox-nightly/firefox-nightly.svg?url"
import firefoxDeveloperEditionIcon from "../../../../node_modules/browser-logos/src/firefox-developer-edition/firefox-developer-edition.svg?url"
gql`fragment OpenBrowserList on App {
gql`
fragment OpenBrowserList on App {
browsers {
name
family
channel
displayName
path
version
majorVersion
name
family
channel
displayName
path
version
majorVersion
}
}`
}
`
const props = defineProps<{
gql: OpenBrowserListFragment,
@@ -135,12 +137,12 @@ const allBrowsers = [{
icon: edgeDevIcon
}]
const getBroswerDetails = (browser) => {
return {
...browser,
displayVersion: `v${browser.version}`,
icon: allBrowsers.find(item => item.displayName === browser.displayName)?.icon,
}
const getBroswerDetails = (browser: OpenBrowserListFragment['browsers'][number]) => {
return {
...browser,
displayVersion: `v${browser.version}`,
icon: allBrowsers.find(item => item.displayName === browser.displayName)?.icon ?? '',
}
}
const isDetected = (browser) => {
@@ -148,6 +150,7 @@ const isDetected = (browser) => {
.find(browserInList => browserInList.displayName === browser.displayName)
}
// TODO(tim): move a lot of this to GraphQL
const displayBrowsers = computed(() => {
const foundValidBrowsers = allBrowsers.filter(isDetected).reduce((acc, curr) => {
const matchingFoundBrowsers = props.gql.browsers.filter(foundBrowser => {
@@ -157,7 +160,8 @@ const displayBrowsers = computed(() => {
acc.push(getBroswerDetails(browser))
})
return acc
}, [])
// TODO: fix up these types w/ GraphQL
}, [] as Array<OpenBrowserListFragment['browsers'][number] & {displayVersion: string, icon: string, disabled?: boolean}>)
return foundValidBrowsers
})
@@ -165,8 +169,6 @@ const displayBrowsers = computed(() => {
const selectedBrowser = ref(displayBrowsers.value[0])
const launchText = computed(() => selectedBrowser.value ? `${t('setupPage.openBrowser.launch')} ${selectedBrowser.value.displayName}` : '')
</script>
<style scoped>

View File

@@ -0,0 +1,6 @@
{
"extends": "../.eslintrc.json",
"rules": {
"no-console": "off"
}
}

View File

@@ -0,0 +1,10 @@
import getenv from 'getenv'
// Where to fetch the remote "federated" schema TODO: add w/ stitching PR
// export const CYPRESS_INTERNAL_CLOUD_ENV = 'production'
export const CYPRESS_INTERNAL_DEBUG_PORT_STARTUP = getenv.int('CYPRESS_INTERNAL_DEBUG_PORT_STARTUP', 7200)
export const CYPRESS_INTERNAL_DEBUG_PORT_ELECTRON = getenv.int('CYPRESS_INTERNAL_DEBUG_PORT_ELECTRON', 7201)
export const CYPRESS_INTERNAL_DEBUG_PORT_CODEGEN = getenv.int('CYPRESS_INTERNAL_DEBUG_PORT_CODEGEN', 7202)

69
scripts/gulp/gulpfile.ts Normal file
View File

@@ -0,0 +1,69 @@
import gulp from 'gulp'
import { autobarrelWatcher } from './tasks/gulpAutobarrel'
import { startCypressWatch } from './tasks/gulpCypress'
import { graphqlCodegen, graphqlCodegenWatch, nexusCodegen, nexusCodegenWatch } from './tasks/gulpGraphql'
import { viteApp, viteCleanApp, viteCleanLaunchpad, viteLaunchpad } from './tasks/gulpVite'
import { makePathMap } from './utils/makePathMap'
gulp.task(
'dev',
gulp.series(
// Autobarrel watcher
autobarrelWatcher,
// Fetch the latest "remote" schema from the Cypress cloud
// TODO: with stitching bracnh
// fetchCloudSchema,
gulp.parallel(
// Clean the vite apps
viteCleanApp,
viteCleanLaunchpad,
),
// Codegen for our GraphQL Server so we have the latest schema to build the frontend codegen correctly
nexusCodegenWatch,
// ... and generate the correct GraphQL types for the frontend
graphqlCodegenWatch,
// Now that we have the codegen, we can start the frontend(s)
gulp.parallel(
viteApp,
viteLaunchpad,
),
// And we're finally ready for electron, watching for changes in /graphql to auto-restart the server
startCypressWatch,
),
)
gulp.task('buildProd', gulp.series(
nexusCodegen,
graphqlCodegen,
))
gulp.task(
'postinstall',
gulp.series(
gulp.parallel(
// Clean the vite apps
viteCleanApp,
viteCleanLaunchpad,
),
'buildProd',
),
)
// gulp.task(
// 'devLegacy', // Tim: TODO
// )
// gulp.task(
// 'debug', // Tim: TODO
// )
gulp.task(makePathMap)
gulp.task(nexusCodegen)
gulp.task(nexusCodegenWatch)
gulp.task(graphqlCodegen)
gulp.task(graphqlCodegenWatch)

View File

@@ -0,0 +1,34 @@
/* eslint-disable */
// Auto-generated by makePathMap.ts
import path from 'path'
export const monorepoPaths = {
root: path.join(__dirname, '../..'),
pkgDir: path.join(__dirname, '../../packages'),
pkgApp: path.join(__dirname, '../../packages/app'),
pkgDesktopGui: path.join(__dirname, '../../packages/desktop-gui'),
pkgDriver: path.join(__dirname, '../../packages/driver'),
pkgElectron: path.join(__dirname, '../../packages/electron'),
pkgExample: path.join(__dirname, '../../packages/example'),
pkgExtension: path.join(__dirname, '../../packages/extension'),
pkgFrontendShared: path.join(__dirname, '../../packages/frontend-shared'),
pkgGraphql: path.join(__dirname, '../../packages/graphql'),
pkgHttpsProxy: path.join(__dirname, '../../packages/https-proxy'),
pkgLauncher: path.join(__dirname, '../../packages/launcher'),
pkgLaunchpad: path.join(__dirname, '../../packages/launchpad'),
pkgNetStubbing: path.join(__dirname, '../../packages/net-stubbing'),
pkgNetwork: path.join(__dirname, '../../packages/network'),
pkgProxy: path.join(__dirname, '../../packages/proxy'),
pkgReporter: path.join(__dirname, '../../packages/reporter'),
pkgResolveDist: path.join(__dirname, '../../packages/resolve-dist'),
pkgRewriter: path.join(__dirname, '../../packages/rewriter'),
pkgRoot: path.join(__dirname, '../../packages/root'),
pkgRunner: path.join(__dirname, '../../packages/runner'),
pkgRunnerCt: path.join(__dirname, '../../packages/runner-ct'),
pkgRunnerShared: path.join(__dirname, '../../packages/runner-shared'),
pkgServer: path.join(__dirname, '../../packages/server'),
pkgSocket: path.join(__dirname, '../../packages/socket'),
pkgTs: path.join(__dirname, '../../packages/ts'),
pkgTypes: path.join(__dirname, '../../packages/types'),
pkgUiComponents: path.join(__dirname, '../../packages/ui-components'),
pkgWebConfig: path.join(__dirname, '../../packages/web-config')
}

View File

@@ -0,0 +1,17 @@
import { resolveAutobarrelConfig, autobarrelWatch } from 'autobarrel'
import path from 'path'
import { monorepoPaths } from '../monorepoPaths'
/**
* Creates "barrel" files according to config in autobarrel.json:
* https://github.com/tgriesser/autobarrel
* Particularly useful in @packages/graphql because we want to import all
* types into the root schema
*/
export async function autobarrelWatcher () {
await autobarrelWatch(
await resolveAutobarrelConfig({
path: path.join(monorepoPaths.root, 'autobarrel.json'),
}),
)
}

View File

@@ -0,0 +1,89 @@
import chokidar from 'chokidar'
import path from 'path'
import childProcess, { ChildProcess } from 'child_process'
import pDefer from 'p-defer'
import { monorepoPaths } from '../monorepoPaths'
/**
* Starts cypress, but watches the GraphQL files & restarts the server
* when any of those change
*/
export function startCypressWatch () {
const watcher = chokidar.watch('src/**/*.{js,ts}', {
cwd: monorepoPaths.pkgGraphql,
ignored: /\.gen\.ts/,
ignoreInitial: true,
})
let child: ChildProcess | null = null
let isClosing = false
let isRestarting = false
const argv = process.argv.slice(3)
const pathToCli = path.resolve(monorepoPaths.root, 'cli', 'bin', 'cypress')
function openServer () {
if (child) {
child.removeAllListeners()
}
if (!argv.includes('--project') && !argv.includes('--global')) {
argv.push('--global')
}
if (!argv.includes('--dev')) {
argv.push('--dev')
}
child = childProcess.fork(pathToCli, ['open', ...argv], {
stdio: 'inherit',
execArgv: [],
env: {
...process.env,
LAUNCHPAD: '1',
CYPRESS_INTERNAL_DEV_WATCH: 'true',
},
})
child.on('exit', (code) => {
if (isClosing) {
process.exit(code ?? 0)
}
})
child.on('disconnect', () => {
child = null
})
}
async function restartServer () {
if (isRestarting) {
return
}
const dfd = pDefer()
if (child) {
child.on('exit', dfd.resolve)
isRestarting = true
child.send('close')
} else {
dfd.resolve()
}
await dfd.promise
isRestarting = false
openServer()
}
watcher.on('add', restartServer)
watcher.on('change', restartServer)
openServer()
process.on('beforeExit', () => {
isClosing = true
child?.send('close')
})
}

View File

@@ -0,0 +1,77 @@
import path from 'path'
import pDefer from 'p-defer'
import chalk from 'chalk'
import { nexusTypegen, watchNexusTypegen } from '../utils/nexusTypegenUtil'
import { monorepoPaths } from '../monorepoPaths'
import { spawned } from '../utils/childProcessUtils'
import { spawn } from 'child_process'
export async function nexusCodegen () {
return nexusTypegen({
cwd: monorepoPaths.pkgGraphql,
filePath: path.join(monorepoPaths.pkgGraphql, 'src/schema.ts'),
outputPath: path.join(monorepoPaths.pkgGraphql, 'src/gen/nxs.gen.ts'),
})
}
/**
* Watches & regenerates the
*/
export async function nexusCodegenWatch () {
return watchNexusTypegen({
cwd: monorepoPaths.pkgGraphql,
watchPaths: [
'src/**/*.ts',
],
filePath: path.join(monorepoPaths.pkgGraphql, 'src/schema.ts'),
outputPath: path.join(monorepoPaths.pkgGraphql, 'src/gen/nxs.gen.ts'),
})
}
export async function graphqlCodegen () {
return spawned('gql-codegen', 'yarn graphql-codegen --config graphql-codegen.yml', {
cwd: monorepoPaths.root,
waitForExit: true,
})
}
export async function graphqlCodegenWatch () {
const spawned = spawn('graphql-codegen', ['--watch', '--config', 'graphql-codegen.yml'], {
cwd: monorepoPaths.root,
})
const dfd = pDefer()
let hasResolved = false
spawned.stdout.on('data', (chunk) => {
const strs = `${chunk}`.split('\n').filter((f) => f)
const timestampRegex = /\[\d{2}:\d{2}:\d{2}\]/
const isFailureBlock = strs.some((s) => s.includes('[failed]'))
strs.forEach((str) => {
let codegenMsg = timestampRegex.test(str) ? str.slice(10) : str
if (codegenMsg.includes('Watching for changes') && !hasResolved) {
dfd.resolve({})
}
if (codegenMsg === str) {
process.stdout.write(
`${chalk.cyan('graphqlCodegen')}: ${chalk.gray(str)}\n`,
)
} else if (codegenMsg.startsWith(' Generate .') || isFailureBlock) {
codegenMsg = codegenMsg.includes('[failed]')
? chalk.red(codegenMsg)
: chalk.yellow(codegenMsg)
process.stdout.write(`${chalk.cyan('graphqlCodegen')}: ${codegenMsg}\n`)
}
})
})
spawned.stderr.on('data', (data) => {
console.error(chalk.red(String(data)))
})
return dfd.promise
}

View File

@@ -0,0 +1,111 @@
import glob from 'glob'
import childProcess from 'child_process'
import util from 'util'
import path from 'path'
import chalk from 'chalk'
import { monorepoPaths } from '../monorepoPaths'
const execAsync = util.promisify(childProcess.exec)
process.on('unhandledRejection', (reason) => {
console.error(reason)
process.exit(1)
})
export function getTsPackages (packagesPath: string = ''): Promise<Set<string>> {
const dfd = {} as Record<string, any>
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
glob(
path.join(monorepoPaths.root, packagesPath, '/packages/*/package.json'),
(err, packageJsons) => {
if (err) {
return dfd.reject(err)
}
type PackageJsonStructure = {
name: string
dependencies: Record<string, string>
devDependencies: Record<string, string>
scripts: Record<string, string>
}
const required = packageJsons.map((path) => {
return require(path)
}) as PackageJsonStructure[]
const packages = new Set<string>()
required.forEach((r) => {
// Select only packages that have build-ts
if (r.scripts && r.scripts['build-ts']) {
packages.add(r.name)
}
})
dfd.resolve(packages)
},
)
return dfd.promise
}
export async function buildPackageTsc ({
packagesPath = '',
tsPackages = new Set(),
onlyPackages,
}: {
packagesPath?: string
tsPackages?: Set<string>
onlyPackages?: string[]
}) {
console.log(
chalk.blue(`TSC: Building deps for ${onlyPackages || 'All Packages'}`),
)
const errors = []
let built = 0
const packages = onlyPackages || [...Array.from(tsPackages)]
for (const pkg of packages) {
try {
await execAsync('tsc', {
cwd: path.join(
__dirname,
'../../',
packagesPath,
`/packages/${pkg.replace(/\@(packages|cypress|frontend)\//, '')}`,
),
})
built++
console.log(
`${chalk.green(`Built`)} ${pkg} ${chalk.magenta(
`${built} / ${packages.length}`,
)}`,
)
} catch (e) {
console.log(
`${chalk.red(`Failed built`)} ${pkg} ${chalk.magenta(
`${built} / ${packages.length}`,
)}`,
)
errors.push({ package: pkg, stdout: e.stdout })
}
}
if (errors.length > 0) {
errors.forEach((e) => {
console.log(`Error building ${e.package}`)
console.error(chalk.red(e.stdout))
})
process.exit(1)
}
}

View File

@@ -0,0 +1,21 @@
import detectPort from 'detect-port'
import { exit } from '../utils/exitUtil'
export async function friendlyStartupWarnings () {
const ALL_SERVER_PORTS_USED = [3000, 4000, 8484, 1234]
const unavaiablePorts: number[] = []
await Promise.all(
ALL_SERVER_PORTS_USED.map(async (port) => {
if (port !== (await detectPort(port))) {
unavaiablePorts.push(port)
}
}),
)
if (unavaiablePorts.length > 0) {
exit(
`The following ports needed by Cypress are already in use: ${unavaiablePorts.join(', ')}.\nCheck that you don't have another web-server running.\nThe command "pkill node -9" can be used to kill all node processes.`,
)
}
}

View File

@@ -0,0 +1,55 @@
import type { SpawnOptions } from 'child_process'
import getenv from 'getenv'
import pDefer from 'p-defer'
import { monorepoPaths } from '../monorepoPaths'
import { AllSpawnableApps, spawned } from '../utils/childProcessUtils'
const CYPRESS_VITE_APP_PORT = getenv.int('CYPRESS_VITE_APP_PORT', 3333)
const CYPRESS_VITE_LAUNCHPAD_PORT = getenv.int('CYPRESS_VITE_LAUNCHPAD_PORT', 3001)
export function viteApp () {
return viteDev('vite-app', `yarn vite --port ${CYPRESS_VITE_APP_PORT} --base /__vite__/`, {
cwd: monorepoPaths.pkgApp,
})
}
export function viteLaunchpad () {
return viteDev('vite-launchpad', `yarn vite --port ${CYPRESS_VITE_LAUNCHPAD_PORT}`, {
cwd: monorepoPaths.pkgLaunchpad,
})
}
export function viteCleanApp () {
return spawned('vite-clean', `yarn clean`, {
cwd: monorepoPaths.pkgApp,
})
}
export function viteCleanLaunchpad () {
return spawned('vite-clean', `yarn clean`, {
cwd: monorepoPaths.pkgLaunchpad,
})
}
function viteDev (
prefix: AllSpawnableApps,
command: string,
opts: SpawnOptions = {},
) {
const dfd = pDefer()
let ready = false
spawned(prefix, command, opts, {
tapOut (chunk, enc, cb) {
if (!ready && String(chunk).includes('dev server running at')) {
ready = true
setTimeout(() => dfd.resolve(), 20) // flush the rest of the chunks
}
cb(null, chunk)
},
})
return dfd.promise
}

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"importsNotUsedAsValues": "error",
"types": []
},
"include": ["**/*"]
}

View File

@@ -0,0 +1,136 @@
import { exec, ExecOptions, spawn, SpawnOptions } from 'child_process'
import through2 from 'through2'
import util from 'util'
// import psTree from 'ps-tree'
// import psNode from 'ps-node'
// import util from 'util'
import { prefixStream } from './prefixStream'
const spawningApps = new Set()
// const killAsync = util.promisify(psNode.kill)
// const psTreeAsync = util.promisify(psTree)
// const runningApps = new Map<
// AllSpawnableApps,
// [ChildProcess, ArgsFor<typeof spawned>, Function]
// >()
export async function allReady () {
while (spawningApps.size > 0) {
await new Promise((ready) => setTimeout(ready, 100))
}
return true
}
export type AllSpawnableApps =
| `vite-${string}`
| `vite:build-${string}`
| 'gql-codegen'
interface SpawnedOptions extends SpawnOptions {
waitForExit?: boolean
}
export async function spawned (
prefix: AllSpawnableApps,
command: string,
opts: SpawnedOptions = {},
tapThrough: {
tapOut?: through2.TransformFunction
tapErr?: through2.TransformFunction
} = {},
) {
const { waitForExit, ...spawnOpts } = opts
spawningApps.add(prefix)
const [executable, ...rest] = command.split(' ')
const cp = spawn(executable, rest, {
stdio: 'pipe',
env: {
FORCE_COLOR: '1',
NODE_ENV: 'development',
...process.env,
},
...spawnOpts,
})
const tapOut = tapThrough.tapOut || null
const tapErr = tapThrough.tapErr || null
const prefixedStdout = cp.stdout?.pipe(
through2(function (chunk, enc, cb) {
if (tapOut) {
tapOut.call(this, chunk, enc, cb)
} else {
cb(null, chunk)
}
}),
)
.pipe(prefixStream(`${prefix}:${cp.pid}`))
const prefixedStderr = cp.stderr?.pipe(
through2(function (chunk, enc, cb) {
if (tapErr) {
tapErr.call(this, chunk, enc, cb)
} else {
cb(null, chunk)
}
}),
)
.pipe(prefixStream(`${prefix}:${cp.pid}`))
prefixedStdout?.pipe(process.stdout)
prefixedStderr?.pipe(process.stderr)
// const cleanup = () => {
// prefixedStdout?.unpipe(process.stdout)
// prefixedStderr?.unpipe(process.stderr)
// }
// runningApps.set(prefix, [cp, [prefix, command, opts], cleanup])
return new Promise((resolve, reject) => {
if (waitForExit) {
cp.once('exit', () => {
resolve(cp)
})
cp.once('error', reject)
} else {
cp.stdout?.once('data', () => {
spawningApps.delete(prefix)
resolve(cp)
})
}
})
}
const execAsyncLocal = util.promisify(exec)
interface ExecAsyncOptions extends ExecOptions {
encoding?: string | null
silent?: boolean
}
export const execAsync = async (
command: string,
options: ExecAsyncOptions = {},
) => {
const { silent } = options
if (!silent) {
console.log(command)
}
const result = await execAsyncLocal(command, options)
if (!silent && typeof result.stdout === 'string' && result.stdout.length) {
console.log(result.stdout)
}
if (!silent && typeof result.stderr === 'string' && result.stderr.length) {
console.error(result.stderr)
}
return result
}

View File

@@ -0,0 +1,13 @@
import chalk from 'chalk'
import dedent from 'dedent'
export function exit (msg: string | Error): void {
if (msg instanceof Error) {
console.log(msg.stack)
return exit(msg.message)
}
console.error(`\n${chalk.red(dedent(msg))}\n`)
process.exit(1)
}

View File

@@ -0,0 +1,42 @@
import fs from 'fs-extra'
import path from 'path'
import _ from 'lodash'
const ROOT_DIR = path.join(__dirname, '../../..')
/**
* Builds
*/
export async function makePathMap () {
const packages = await fs.readdir(path.join(ROOT_DIR, 'packages'))
const dirs = await Promise.all(
packages.map(async (p) => {
try {
await fs.stat(path.join(ROOT_DIR, `packages/${p}/package.json`))
return p
} catch (e) {
return null
}
}),
)
await fs.writeFile(
path.join(__dirname, '../monorepoPaths.ts'),
`/* eslint-disable */
// Auto-generated by makePathMap.ts
import path from 'path'
export const monorepoPaths = {
root: path.join(__dirname, '../..'),
pkgDir: path.join(__dirname, '../../packages'),
${dirs
.filter((f) => f)
.map((dir) => {
return ` ${_.camelCase(
`pkg-${dir}`,
)}: path.join(__dirname, '../../packages/${dir}')`
}).join(',\n')}
}
`,
)
}

View File

@@ -0,0 +1,90 @@
import { spawn, execSync } from 'child_process'
import chalk from 'chalk'
import pDefer from 'p-defer'
import chokidar from 'chokidar'
import _ from 'lodash'
interface NexusTypegenCfg {
cwd: string
/**
* Path to the file we need to execute to generate the schema
*/
filePath: string
outputPath?: string
}
function prefixTypegen (s: string) {
return `${chalk.cyan('nexusTypegen')}: ${s}`
}
export async function nexusTypegen (cfg: NexusTypegenCfg) {
const dfd = pDefer()
if (cfg.outputPath) {
execSync(`touch ${cfg.outputPath}`)
}
const out = spawn('node', ['-r', '@packages/ts/register', cfg.filePath], {
cwd: cfg.cwd,
env: {
...process.env,
CYPRESS_INTERNAL_NEXUS_CODEGEN: 'true',
},
})
out.stderr.on('data', (data) => {
process.stdout.write(prefixTypegen(chalk.red(String(data))))
dfd.resolve({})
})
out.stdout.on('data', (data) => {
const outString = String(data)
.split('\n')
.map((s) => prefixTypegen(chalk.magentaBright(s)))
.join('\n')
process.stdout.write('\n')
process.stdout.write(outString)
process.stdout.write('\n')
dfd.resolve({})
})
out.on('error', dfd.reject)
return dfd.promise
}
let debounced: Record<string, Function> = {}
const nexusTypegenDebounced = (cfg: NexusTypegenCfg) => {
debounced[cfg.filePath] =
debounced[cfg.filePath] ?? _.debounce(nexusTypegen, 500)
debounced[cfg.filePath](cfg)
}
interface NexusTypegenWatchCfg extends NexusTypegenCfg {
watchPaths: string[]
}
export async function watchNexusTypegen (cfg: NexusTypegenWatchCfg) {
const dfd = pDefer()
const watcher = chokidar.watch(cfg.watchPaths, {
cwd: cfg.cwd,
ignored: /\.gen\.ts/,
ignoreInitial: true,
})
watcher.on('all', (evt, path) => {
console.log(prefixTypegen(`${evt} ${path}`))
nexusTypegenDebounced(cfg)
})
watcher.on('ready', () => {
console.log(prefixTypegen(`Codegen Watcher Ready for ${cfg.filePath}`))
nexusTypegen(cfg).then(dfd.resolve, dfd.reject)
})
return dfd.promise
}

View File

@@ -0,0 +1,56 @@
import chalk from 'chalk'
import { Transform } from 'stream'
/**
* Takes a stream and prefixes with a given string
* @param prefixStr
* @returns
*/
export function prefixStream (prefixStr: string | (() => string)) {
const prefix =
typeof prefixStr === 'string'
? Buffer.from(`[${chalk.gray(prefixStr)}]: `)
: () => Buffer.from(`[${chalk.gray(prefixStr())}]: `)
// https://stackoverflow.com/a/45126242
class PrefixStream extends Transform {
_rest?: Buffer
_transform (chunk: Buffer, encoding: string, cb: CallableFunction) {
this._rest =
this._rest && this._rest.length
? Buffer.concat([this._rest, chunk])
: chunk
let index
while (this._rest && (index = this._rest.indexOf('\n')) !== -1) {
const line = this._rest.slice(0, ++index)
this._rest = this._rest.slice(index)
this.push(
Buffer.concat([
typeof prefix === 'function' ? prefix() : prefix,
line,
]),
)
}
cb()
}
_flush (cb: CallableFunction) {
if (this._rest && this._rest.length) {
cb(
null,
Buffer.concat([
typeof prefix === 'function' ? prefix() : prefix,
this._rest,
]),
)
}
}
}
return new PrefixStream()
}

View File

@@ -1,7 +1,6 @@
process.env.GRAPHQL_CODEGEN = 'true'
require('@packages/server')
if (process.argv.includes('--devWatch')) {
if (process.env.CYPRESS_INTERNAL_DEV_WATCH) {
process.on('message', (msg) => {
if (msg === 'close') {
process.exit(0)

View File

@@ -1,68 +0,0 @@
const chokidar = require('chokidar')
const childProcess = require('child_process')
const path = require('path')
const pDefer = require('p-defer')
const watcher = chokidar.watch('packages/graphql/src/**/*.{js,ts}', {
cwd: path.join(__dirname, '..'),
ignored: '**/nxs.gen.ts',
ignoreInitial: true,
})
/**
* @type {childProcess.ChildProcess}
*/
let child
let isClosing = false
let isRestarting = false
function runServer () {
if (child) {
child.removeAllListeners()
}
child = childProcess.fork(path.join(__dirname, 'start.js'), [...process.argv, '--devWatch'], {
stdio: 'inherit',
})
child.on('exit', (code) => {
if (isClosing) {
process.exit(code)
}
})
child.on('disconnect', () => {
child = null
})
}
async function restartServer () {
if (isRestarting) {
return
}
const dfd = pDefer()
if (child) {
child.on('exit', dfd.resolve)
isRestarting = true
child.send('close')
} else {
dfd.resolve()
}
await dfd.promise
isRestarting = false
runServer()
}
watcher.on('add', restartServer)
watcher.on('change', restartServer)
runServer()
process.on('beforeExit', () => {
isClosing = true
child?.send('close')
})

117
yarn.lock
View File

@@ -3176,6 +3176,18 @@
lodash "~4.17.0"
tslib "~2.3.0"
"@graphql-codegen/plugin-helpers@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.1.1.tgz#fc13e735763574ef308045bbb95c3e7201ec0027"
integrity sha512-7jjN9fekMQkpd7cRTbaBxgqt/hkR3CXeOUSsEyHFDDHKtvCrnev3iyc75IeWXpO9tOwDE8mVPTzEZnu4QukrNA==
dependencies:
"@graphql-tools/utils" "^8.1.1"
change-case-all "1.0.14"
common-tags "1.8.0"
import-from "4.0.0"
lodash "~4.17.0"
tslib "~2.3.0"
"@graphql-codegen/typed-document-node@^1.18.9":
version "1.18.9"
resolved "https://registry.yarnpkg.com/@graphql-codegen/typed-document-node/-/typed-document-node-1.18.9.tgz#36f382a5e5a30844403dd078d97d84b362e77dcf"
@@ -3430,6 +3442,13 @@
camel-case "4.1.2"
tslib "~2.2.0"
"@graphql-tools/utils@^8.1.1":
version "8.2.2"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.2.2.tgz#d29420bf1003d2876cb30f373145be432c7f7c4b"
integrity sha512-29FFY5U4lpXuBiW9dRvuWnBVwGhWbGLa2leZcAMU/Pz47Cr/QLZGVgpLBV9rt+Gbs7wyIJM7t7EuksPs0RDm3g==
dependencies:
tslib "~2.3.0"
"@graphql-tools/wrap@^7.0.4":
version "7.0.8"
resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-7.0.8.tgz#ad41e487135ca3ea1ae0ea04bb3f596177fb4f50"
@@ -8341,6 +8360,11 @@
resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050"
integrity sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A==
"@types/detect-port@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.1.tgz#a1af9bb9e8e43f5a2190f876cfd4120a5fae41ab"
integrity sha512-evutJ8HynqPgm07LaG7nj7VqFqfAYpAjpKYYjhj5rlD5ukdF0hFiqHQo94Tu1FBJQkWDQPt3f1DaXLOGEL1nAw==
"@types/enzyme-adapter-react-16@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.5.tgz#1bf30a166f49be69eeda4b81e3f24113c8b4e9d5"
@@ -8404,6 +8428,11 @@
dependencies:
"@types/node" "*"
"@types/expect@^1.20.4":
version "1.20.4"
resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
"@types/express-serve-static-core@*":
version "4.17.18"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz#8371e260f40e0e1ca0c116a9afcd9426fa094c40"
@@ -8448,11 +8477,26 @@
dependencies:
"@types/node" "*"
"@types/getenv@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/getenv/-/getenv-1.0.0.tgz#fa5e6901e9fb84bfb40205d4952fd06c8afcf006"
integrity sha512-w8qs+09o4pfFb/4XkHJzsHEZ2m36s/d9vJhglbOeSiSe9mPu0OmCQbU4iEgGl2DNP9WfOHCVd6fBwIvBd4AZhg==
dependencies:
"@types/node" "*"
"@types/glob-base@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@types/glob-base/-/glob-base-0.3.0.tgz#a581d688347e10e50dd7c17d6f2880a10354319d"
integrity sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0=
"@types/glob-stream@*":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.1.tgz#c792d8d1514278ff03cad5689aba4c4ab4fbc805"
integrity sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==
dependencies:
"@types/glob" "*"
"@types/node" "*"
"@types/glob@*", "@types/glob@7.1.1", "@types/glob@^7.1.1":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
@@ -8469,6 +8513,15 @@
dependencies:
"@types/node" "*"
"@types/gulp@^4.0.9":
version "4.0.9"
resolved "https://registry.yarnpkg.com/@types/gulp/-/gulp-4.0.9.tgz#a2f9667bcc26bc72b4899dd16216d6584a12346c"
integrity sha512-zzT+wfQ8uwoXjDhRK9Zkmmk09/fbLLmN/yDHFizJiEKIve85qutOnXcP/TM2sKPBTU+Jc16vfPbOMkORMUBN7Q==
dependencies:
"@types/undertaker" "*"
"@types/vinyl-fs" "*"
chokidar "^3.3.1"
"@types/hast@^2.0.0":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9"
@@ -9008,6 +9061,13 @@
resolved "https://registry.yarnpkg.com/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz#1c3df624bfc4b62f992d3012b84c56d41eab3776"
integrity sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==
"@types/through2@^2.0.36":
version "2.0.36"
resolved "https://registry.yarnpkg.com/@types/through2/-/through2-2.0.36.tgz#35fda0db635827d44c0e08e2c94653e647574a00"
integrity sha512-vuifQksQHJXhV9McpVsXKuhnf3lsoX70PnhcqIAbs9dqLH2NgrGz0DzZPDY3+Yh6eaRqcE1gnCQ6QhBn1/PT5A==
dependencies:
"@types/node" "*"
"@types/through@*":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
@@ -9027,11 +9087,42 @@
dependencies:
source-map "^0.6.1"
"@types/undertaker-registry@*":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz#4306d4a03d7acedb974b66530832b90729e1d1da"
integrity sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==
"@types/undertaker@*":
version "1.2.7"
resolved "https://registry.yarnpkg.com/@types/undertaker/-/undertaker-1.2.7.tgz#89c37fd3be556141a4092b38f8bc503076803d21"
integrity sha512-xuY7nBwo1zSRoY2aitp/HArHfTulFAKql2Fr4b4mWbBBP+F50n7Jm6nwISTTMaDk2xvl92O10TTejVF0Q9mInw==
dependencies:
"@types/node" "*"
"@types/undertaker-registry" "*"
async-done "~1.3.2"
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
"@types/vinyl-fs@*":
version "2.4.12"
resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.12.tgz#7b4673d9b4d5a874c8652d10f0f0265479014c8e"
integrity sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==
dependencies:
"@types/glob-stream" "*"
"@types/node" "*"
"@types/vinyl" "*"
"@types/vinyl@*":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.6.tgz#b2d134603557a7c3d2b5d3dc23863ea2b5eb29b0"
integrity sha512-ayJ0iOCDNHnKpKTgBG6Q6JOnHTj9zFta+3j2b8Ejza0e4cvRyMn0ZoLEmbPrTHe5YYRlDYPvPWVdV4cTaRyH7g==
dependencies:
"@types/expect" "^1.20.4"
"@types/node" "*"
"@types/warning@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
@@ -11441,7 +11532,7 @@ async-array-reduce@^0.2.0:
resolved "https://registry.yarnpkg.com/async-array-reduce/-/async-array-reduce-0.2.1.tgz#c8be010a2b5cd00dea96c81116034693dfdd82d1"
integrity sha1-yL4BCitc0A3qlsgRFgNGk9/dgtE=
async-done@^1.2.0, async-done@^1.2.2:
async-done@^1.2.0, async-done@^1.2.2, async-done@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2"
integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==
@@ -11542,6 +11633,16 @@ auto-bind@~4.0.0:
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
autobarrel@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/autobarrel/-/autobarrel-1.1.0.tgz#61ec469f8f7195193df3cf93598e9e673c2eb5ae"
integrity sha512-QV3h7saAebtHHmeF0Pk+sVPHOOIvg/TEejy39mfyQposD3twP3p4IyDQeYAVjf8K4VNH3m4M5WFARd2f2PFCPw==
dependencies:
chokidar "^3.4.0"
glob "^7.1.6"
minimist "^1.2.5"
tslib "^2.0.0"
autoprefixer@10.2.4:
version "10.2.4"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1"
@@ -14451,7 +14552,7 @@ chokidar@3.5.1:
optionalDependencies:
fsevents "~2.3.1"
"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.2.3, chokidar@^3.3.0, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.0, chokidar@^3.5.1, chokidar@^3.5.2:
"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.2.3, chokidar@^3.3.0, chokidar@^3.3.1, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.0, chokidar@^3.5.1, chokidar@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
@@ -21142,6 +21243,11 @@ get-value@^2.0.3, get-value@^2.0.6:
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
getenv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31"
integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==
getos@3.2.1, getos@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5"
@@ -30411,6 +30517,11 @@ p-defer@^1.0.0:
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
p-defer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83"
integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==
p-each-series@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71"
@@ -38863,7 +38974,7 @@ through2@^3.0.0, through2@^3.0.1:
inherits "^2.0.4"
readable-stream "2 || 3"
through2@^4.0.0:
through2@^4.0.0, through2@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764"
integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==