diff --git a/@app/db/.gmrc b/@app/db/.gmrc index def3dbc5..c0aa1d06 100644 --- a/@app/db/.gmrc +++ b/@app/db/.gmrc @@ -80,7 +80,7 @@ "_": "command", "shadow": true, // NOTE: this script does nothing when envvar `IN_TESTS` is `1` - "command": "node scripts/dump-db.js" + "command": "zx scripts/dump-db.mjs" } ], @@ -93,7 +93,7 @@ "_": "command", "shadow": true, // NOTE: this script does nothing unless envvar `IN_TESTS` is `1` - "command": "node scripts/test-seed.js" + "command": "zx scripts/test-seed.mjs" } ], diff --git a/@app/db/scripts/dump-db.js b/@app/db/scripts/dump-db.mjs similarity index 90% rename from @app/db/scripts/dump-db.js rename to @app/db/scripts/dump-db.mjs index 1ed2e30e..4b492a38 100644 --- a/@app/db/scripts/dump-db.js +++ b/@app/db/scripts/dump-db.mjs @@ -1,4 +1,6 @@ -const { spawn } = require("child_process"); +#!/usr/bin/env zx + +import { spawn } from "child_process"; if (process.env.IN_TESTS === "1") { process.exit(0); diff --git a/@app/db/scripts/test-seed.js b/@app/db/scripts/test-seed.mjs similarity index 75% rename from @app/db/scripts/test-seed.js rename to @app/db/scripts/test-seed.mjs index 75811eb5..7ce4de3f 100644 --- a/@app/db/scripts/test-seed.js +++ b/@app/db/scripts/test-seed.mjs @@ -1,5 +1,9 @@ -const { writeFile } = require("fs").promises; -const pg = require("pg"); +#!/usr/bin/env zx + +import pg from "pg"; +import { fs } from "zx"; + +const { Pool } = pg; if (process.env.IN_TESTS !== "1") { process.exit(0); @@ -10,10 +14,10 @@ async function main() { if (!connectionString) { throw new Error("GM_DBURL not set!"); } - const pgPool = new pg.Pool({ connectionString }); + const pgPool = new Pool({ connectionString }); try { await pgPool.query("delete from graphile_worker.jobs;"); - await writeFile( + await fs.writeFile( `${__dirname}/../__tests__/jest.watch.hack.ts`, `export const ts = ${Date.now()};\n` ); diff --git a/docker/package.json b/docker/package.json index be9bb251..6a5ccb2b 100644 --- a/docker/package.json +++ b/docker/package.json @@ -3,7 +3,7 @@ "private": true, "version": "0.0.0", "scripts": { - "setup": "node ./scripts/yarn-setup.js", + "setup": "zx ./scripts/yarn-setup.mjs", "start": "yarn compose up server", "bash": "yarn compose exec server bash", "dev": "yarn compose:exec:dev bash", @@ -13,7 +13,7 @@ "db:up": "yarn compose up -d db", "compose": "docker-compose -f ../docker-compose.yml", "compose:exec:dev": "yarn down && yarn compose up -d dev && yarn compose exec dev ", - "reset:volumes": "node ./scripts/clean-volumes.js", + "reset:volumes": "zx ./scripts/clean-volumes.mjs", "rebuild": "yarn compose build", "down": "yarn compose down --remove-orphans" }, diff --git a/docker/scripts/clean-volumes.js b/docker/scripts/clean-volumes.js deleted file mode 100644 index dfffd2cf..00000000 --- a/docker/scripts/clean-volumes.js +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node -const { execSync } = require("child_process"); -const { basename, dirname, resolve } = require("path"); - -const projectName = basename(dirname(resolve(__dirname, ".."))).replace( - /[^a-z0-9]/g, - "" -); - -try { - execSync( - `docker volume rm ${projectName}_vscode-extensions ${projectName}_devcontainer_db-volume ${projectName}_devcontainer_node_modules-volume ${projectName}_devcontainer_vscode-extensions`, - { stdio: "inherit" } - ); -} catch (e) { - /* noop */ -} diff --git a/docker/scripts/clean-volumes.mjs b/docker/scripts/clean-volumes.mjs new file mode 100644 index 00000000..ec3c7c94 --- /dev/null +++ b/docker/scripts/clean-volumes.mjs @@ -0,0 +1,14 @@ +#!/usr/bin/env zx + +const { basename, dirname, resolve } = path; + +const projectName = basename(dirname(resolve(__dirname, ".."))).replace( + /[^a-z0-9]/g, + "" +); + +try { + await $`docker volume rm ${projectName}_vscode-extensions ${projectName}_devcontainer_db-volume ${projectName}_devcontainer_node_modules-volume ${projectName}_devcontainer_vscode-extensions`; +} catch (e) { + /* noop */ +} diff --git a/docker/scripts/yarn-setup.js b/docker/scripts/yarn-setup.mjs similarity index 81% rename from docker/scripts/yarn-setup.js rename to docker/scripts/yarn-setup.mjs index ece48fc7..1b5f227e 100644 --- a/docker/scripts/yarn-setup.js +++ b/docker/scripts/yarn-setup.mjs @@ -1,10 +1,10 @@ -const { runSync } = require("../../scripts/lib/run"); -const { basename, dirname, resolve } = require("path"); -const platform = require("os").platform(); -const { safeRandomString } = require("../../scripts/lib/random"); -const fs = require("fs"); -const fsp = fs.promises; +#!/usr/bin/env zx +import { $, fs, path } from "zx"; +import { safeRandomString } from "../../scripts/lib/random.mjs"; + +const { basename, dirname, resolve } = path; +const platform = os.platform(); const DOCKER_DOTENV_PATH = `${__dirname}/../.env`; if (platform !== "win32" && !process.env.UID) { @@ -17,7 +17,7 @@ if (platform !== "win32" && !process.env.UID) { async function main() { // Check that docker/.env exists try { - await fsp.access(DOCKER_DOTENV_PATH, fs.constants.F_OK); + await fs.access(DOCKER_DOTENV_PATH, fs.constants.F_OK); } catch (e) { // Does not exist, write it const password = safeRandomString(30); @@ -46,7 +46,7 @@ POSTGRES_PASSWORD=${password} DATABASE_HOST=db ROOT_DATABASE_URL=postgres://postgres:${password}@db/postgres `; - await fsp.writeFile(DOCKER_DOTENV_PATH, data); + await fs.writeFile(DOCKER_DOTENV_PATH, data); } // The `docker-compose` project name defaults to the directory name containing @@ -58,11 +58,11 @@ ROOT_DATABASE_URL=postgres://postgres:${password}@db/postgres // On Windows we must run 'yarn.cmd' rather than 'yarn' const yarnCmd = platform === "win32" ? "yarn.cmd" : "yarn"; - runSync(yarnCmd, ["down"]); - runSync(yarnCmd, ["db:up"]); + await $`${yarnCmd} down`; + await $`${yarnCmd} db:up`; // Fix permissions - runSync(yarnCmd, [ + await $`${yarnCmd} ${[ "compose", "run", "server", @@ -70,10 +70,10 @@ ROOT_DATABASE_URL=postgres://postgres:${password}@db/postgres "bash", "-c", "chmod o+rwx /var/run/docker.sock && chown -R node /work/node_modules /work/@app/*/node_modules", - ]); + ]}`; // Run setup as normal - runSync(yarnCmd, [ + await $`${yarnCmd} ${[ "compose", "run", "-e", @@ -81,7 +81,7 @@ ROOT_DATABASE_URL=postgres://postgres:${password}@db/postgres "server", "yarn", "setup", - ]); + ]}`; } main().catch((e) => { diff --git a/package.json b/package.json index a286e90c..307cbf40 100644 --- a/package.json +++ b/package.json @@ -5,24 +5,24 @@ "description": "Description of project here", "scripts": { "setup": "yarn && yarn setup:env auto && yarn setup:db && yarn setup:packages", - "setup:env": "node ./scripts/setup_env.js", - "setup:db": "node ./scripts/setup_db.js", + "setup:env": "zx ./scripts/setup_env.mjs", + "setup:db": "zx ./scripts/setup_db.mjs", "setup:packages": "lerna run setup", - "start": "node ./scripts/start.js", + "start": "zx ./scripts/start.mjs", "pretest": "lerna run pretest", - "test": "node scripts/test.js", + "test": "zx scripts/test.mjs", "posttest": "lerna run posttest", - "test:watch": "node scripts/test.js --watch", + "test:watch": "zx scripts/test.mjs --watch", "lint": "tsc -b && yarn prettier:all --check && yarn eslint .", "lint:fix": "yarn eslint --fix . && yarn prettier:all --write", - "eslint": "eslint --ext .js,.jsx,.ts,.tsx,.graphql", - "prettier:all": "prettier --ignore-path .eslintignore \"**/*.{js,jsx,ts,tsx,graphql,md}\"", + "eslint": "eslint --ext .js,.mjs,.jsx,.ts,.tsx,.graphql", + "prettier:all": "prettier --ignore-path .eslintignore \"**/*.{js,mjs,jsx,ts,tsx,graphql,md}\"", "depcheck": "lerna exec --stream \"yarn depcheck --ignores=\"@app/config,@app/client,tslib,webpack,babel-plugin-import,source-map-support,@graphql-codegen/*,*eslint*,@typescript-eslint/*,graphql-toolkit,net,tls,dayjs\" --ignore-dirs=\".next\"\"", "dev": "yarn && lerna run codegen --stream && tsc -b && concurrently --kill-others --names \"TSC,WATCH,RUN,TEST\" --prefix \"({name})\" --prefix-colors \"yellow.bold,yellow.bold,cyan.bold,greenBright.bold\" \"tsc -b --watch --preserveWatchOutput\" \"lerna run --parallel watch\" \"lerna run --parallel dev\" \"yarn test:watch --delay 10\"", "build": "lerna run build", "licenses": "yarn --silent licenses generate-disclaimer > LICENSES.md", - "clean": "node ./scripts/clean.js", - "reset": "yarn clean && node ./scripts/delete-env-file.js", + "clean": "zx ./scripts/clean.mjs", + "reset": "yarn clean && zx ./scripts/delete-env-file.mjs", "--shortcuts to run commands in workspaces--": "", "client": "yarn workspace @app/client", "components": "yarn workspace @app/components", @@ -41,7 +41,8 @@ "abort-controller": "^3.0.0", "graphql": "^15.4.0", "lerna": "^4.0.0", - "string-width": "^5.0.0" + "string-width": "^5.0.0", + "zx": "^4.1.1" }, "devDependencies": { "@babel/core": "^7.14.3", @@ -83,23 +84,15 @@ "pg-connection-string": "2.x" }, "workspaces": { - "packages": [ - "@app/*", - "docker" - ], - "nohoist": [ - "**/cypress" - ] + "packages": ["@app/*", "docker"], + "nohoist": ["**/cypress"] }, "prettier": { "trailingComma": "es5", "proseWrap": "always", "overrides": [ { - "files": [ - "*.yml", - "*.yaml" - ], + "files": ["*.yml", "*.yaml"], "options": { "printWidth": 120 } diff --git a/scripts/_setup_utils.js b/scripts/_setup_utils.mjs similarity index 84% rename from scripts/_setup_utils.js rename to scripts/_setup_utils.mjs index b06a4dfd..b335d58c 100644 --- a/scripts/_setup_utils.js +++ b/scripts/_setup_utils.mjs @@ -1,25 +1,20 @@ +import { fs, os } from "zx"; + +import { readDotenv, withDotenvUpdater } from "./lib/dotenv.mjs"; +import { safeRandomString } from "./lib/random.mjs"; + if (parseInt(process.version.split(".")[0], 10) < 10) { throw new Error("This project requires Node.js >= 10.0.0"); } -const fsp = require("fs").promises; -const { runSync } = require("./lib/run"); -const { withDotenvUpdater, readDotenv } = require("./lib/dotenv"); -const { safeRandomString } = require("./lib/random"); - // fixes runSync not throwing ENOENT on windows -const platform = require("os").platform(); -const yarnCmd = platform === "win32" ? "yarn.cmd" : "yarn"; +export const yarnCmd = os.platform() === "win32" ? "yarn.cmd" : "yarn"; -const projectName = process.env.PROJECT_NAME; +export const projectName = process.env.PROJECT_NAME; -exports.withDotenvUpdater = withDotenvUpdater; -exports.readDotenv = readDotenv; -exports.runSync = runSync; -exports.yarnCmd = yarnCmd; -exports.projectName = projectName; +export { readDotenv, withDotenvUpdater }; -exports.updateDotenv = function updateDotenv(add, answers) { +export function updateDotenv(add, answers) { add( "GRAPHILE_LICENSE", null, @@ -142,11 +137,11 @@ exports.updateDotenv = function updateDotenv(add, answers) { # The name of the folder you cloned graphile-starter to (so we can run docker-compose inside a container):` ); } -}; +} -exports.checkGit = async function checkGit() { +export async function checkGit() { try { - const gitStat = await fsp.stat(`${__dirname}/../.git`); + const gitStat = await fs.stat(`${__dirname}/../.git`); if (!gitStat || !gitStat.isDirectory()) { throw new Error("No .git folder found"); } @@ -170,16 +165,16 @@ exports.checkGit = async function checkGit() { console.error(); process.exit(1); } -}; +} -exports.runMain = (main) => { +export const runMain = (main) => { main().catch((e) => { console.error(e); process.exit(1); }); }; -exports.outro = (message) => { +export const outro = (message) => { console.log(); console.log(); console.log("____________________________________________________________"); diff --git a/scripts/clean.js b/scripts/clean.js deleted file mode 100755 index f111e995..00000000 --- a/scripts/clean.js +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env node -try { - const rimraf = require("rimraf"); - - rimraf.sync(`${__dirname}/../@app/*/dist`); - rimraf.sync(`${__dirname}/../@app/*/tsconfig.tsbuildinfo`); - rimraf.sync(`${__dirname}/../@app/client/.next`); -} catch (e) { - console.error("Failed to clean up, perhaps rimraf isn't installed?"); - console.error(e); -} diff --git a/scripts/clean.mjs b/scripts/clean.mjs new file mode 100755 index 00000000..33686f56 --- /dev/null +++ b/scripts/clean.mjs @@ -0,0 +1,14 @@ +#!/usr/bin/env node + +import { $ } from "zx"; + +void (async function () { + try { + await $`rm -rf ${__dirname}/../@app/*/dist`; + await $`rm -rf ${__dirname}/../@app/*/tsconfig.tsbuildinfo`; + await $`rm -rf ${__dirname}/../@app/client/.next`; + } catch (e) { + console.error("Failed to clean up"); + console.error(e); + } +})(); diff --git a/scripts/delete-env-file.js b/scripts/delete-env-file.js deleted file mode 100755 index 5432b89e..00000000 --- a/scripts/delete-env-file.js +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env node -const fs = require("fs"); - -try { - fs.unlinkSync(`${__dirname}/../.env`); -} catch (e) { - /* NOOP */ -} diff --git a/scripts/delete-env-file.mjs b/scripts/delete-env-file.mjs new file mode 100755 index 00000000..b23a086a --- /dev/null +++ b/scripts/delete-env-file.mjs @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +import { fs } from "zx"; + +void (async function () { + try { + await fs.unlink(`${__dirname}/../.env`); + } catch (e) { + /* NOOP */ + } +})(); diff --git a/scripts/lib/dotenv.js b/scripts/lib/dotenv.mjs similarity index 82% rename from scripts/lib/dotenv.js rename to scripts/lib/dotenv.mjs index c43b5e26..514f5910 100644 --- a/scripts/lib/dotenv.js +++ b/scripts/lib/dotenv.mjs @@ -1,12 +1,12 @@ -const fsp = require("fs").promises; -const dotenv = require("dotenv"); +import dotenv from "dotenv"; +import { fs } from "zx"; -const DOTENV_PATH = `${__dirname}/../../.env`; +const DOTENV_PATH = `${__dirname}/../.env`; -async function readDotenv() { +export async function readDotenv() { let buffer = null; try { - buffer = await fsp.readFile(DOTENV_PATH); + buffer = await fs.readFile(DOTENV_PATH); } catch (e) { /* noop */ } @@ -33,10 +33,10 @@ function encodeDotenvValue(str) { return str; } -async function withDotenvUpdater(overrides, callback) { +export async function withDotenvUpdater(overrides, callback) { let data; try { - data = await fsp.readFile(DOTENV_PATH, "utf8"); + data = await fs.readFile(DOTENV_PATH, "utf8"); // Trim whitespace, and prefix with newline so we can do easier checking later data = "\n" + data.trim(); } catch (e) { @@ -83,8 +83,5 @@ async function withDotenvUpdater(overrides, callback) { data = data.trim() + "\n"; - await fsp.writeFile(DOTENV_PATH, data); + await fs.writeFile(DOTENV_PATH, data); } - -exports.readDotenv = readDotenv; -exports.withDotenvUpdater = withDotenvUpdater; diff --git a/scripts/lib/random.js b/scripts/lib/random.mjs similarity index 59% rename from scripts/lib/random.js rename to scripts/lib/random.mjs index ea9eba89..a2a7841c 100644 --- a/scripts/lib/random.js +++ b/scripts/lib/random.mjs @@ -1,11 +1,9 @@ -const { randomBytes } = require("crypto"); +import { randomBytes } from "crypto"; -function safeRandomString(length) { +export function safeRandomString(length) { // Roughly equivalent to shell `openssl rand -base64 30 | tr '+/' '-_'` return randomBytes(length) .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_"); } - -exports.safeRandomString = safeRandomString; diff --git a/scripts/lib/run.js b/scripts/lib/run.js deleted file mode 100644 index d6ad7116..00000000 --- a/scripts/lib/run.js +++ /dev/null @@ -1,48 +0,0 @@ -const { spawnSync } = require("child_process"); - -const runSync = (cmd, args, options = {}) => { - const result = spawnSync(cmd, args, { - stdio: ["inherit", "inherit", "inherit"], - windowsHide: true, - ...options, - env: { - ...process.env, - YARN_SILENT: "1", - npm_config_loglevel: "silent", - ...options.env, - }, - }); - - const { error, status, signal, stderr, stdout } = result; - - if (error) { - throw error; - } - - if (status || signal) { - if (stdout) { - console.log(stdout.toString("utf8")); - } - if (stderr) { - console.error(stderr.toString("utf8")); - } - if (status) { - process.exitCode = status; - throw new Error( - `Process exited with status '${status}' (running '${cmd} ${ - args ? args.join(" ") : "" - }')` - ); - } else { - throw new Error( - `Process exited due to signal '${signal}' (running '${cmd} ${ - args ? args.join(" ") : null - }')` - ); - } - } - - return result; -}; - -exports.runSync = runSync; diff --git a/scripts/run-docker-with-env.js b/scripts/run-docker-with-env.mjs similarity index 51% rename from scripts/run-docker-with-env.js rename to scripts/run-docker-with-env.mjs index 22c1d1d9..8aabd874 100755 --- a/scripts/run-docker-with-env.js +++ b/scripts/run-docker-with-env.mjs @@ -1,6 +1,9 @@ #!/usr/bin/env node -require("dotenv").config(); -const { runSync } = require("./lib/run"); + +import dotenv from "dotenv"; +import { $ } from "zx"; + +dotenv.config(); const { DATABASE_OWNER, @@ -20,28 +23,16 @@ const DATABASE_HOST = "172.17.0.1"; const DATABASE_URL = `postgres://${DATABASE_OWNER}:${DATABASE_OWNER_PASSWORD}@${DATABASE_HOST}/${DATABASE_NAME}`; const AUTH_DATABASE_URL = `postgres://${DATABASE_AUTHENTICATOR}:${DATABASE_AUTHENTICATOR_PASSWORD}@${DATABASE_HOST}/${DATABASE_NAME}`; -runSync("docker", [ - "run", - "--rm", - "-it", - "--init", - "-p", - "5678:5678", - "-e", - `DATABASE_VISITOR=${DATABASE_VISITOR}`, - "-e", - `GRAPHILE_LICENSE=${GRAPHILE_LICENSE}`, - "-e", - `SECRET=${SECRET}`, - "-e", - `JWT_SECRET=${JWT_SECRET}`, - "-e", - `DATABASE_URL=${DATABASE_URL}`, - "-e", - `AUTH_DATABASE_URL=${AUTH_DATABASE_URL}`, - "-e", - `GITHUB_KEY=${GITHUB_KEY}`, - "-e", - `GITHUB_SECRET=${GITHUB_SECRET}`, - process.argv[2], -]); +void async function () { + await $`docker run --rm -it --init -p 5678:5678${[ + `-e DATABASE_VISITOR=${DATABASE_VISITOR}`, + `-e GRAPHILE_LICENSE=${GRAPHILE_LICENSE}`, + `-e SECRET=${SECRET}`, + `-e JWT_SECRET=${JWT_SECRET}`, + `-e DATABASE_URL=${DATABASE_URL}`, + `-e AUTH_DATABASE_URL=${AUTH_DATABASE_URL}`, + `-e GITHUB_KEY=${GITHUB_KEY}`, + `-e GITHUB_SECRET=${GITHUB_SECRET}`, + `${process.argv[2]}`, + ]}`; +}; diff --git a/scripts/setup_db.js b/scripts/setup_db.mjs similarity index 90% rename from scripts/setup_db.js rename to scripts/setup_db.mjs index 633dd4b9..8a981be0 100644 --- a/scripts/setup_db.js +++ b/scripts/setup_db.mjs @@ -1,23 +1,23 @@ -#!/usr/bin/env node -const { - yarnCmd, - runMain, +#!/usr/bin/env zx + +import dotenv from "dotenv"; +import inquirer from "inquirer"; +import pg from "pg"; +import { $ } from "zx"; + +import { checkGit, outro, - runSync, projectName, -} = require("./_setup_utils"); -const inquirer = require("inquirer"); -const dotenv = require("dotenv"); -const pg = require("pg"); - -const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + runMain, + yarnCmd, +} from "./_setup_utils.mjs"; runMain(async () => { await checkGit(); // Ensure server build has been run - runSync(yarnCmd, ["server", "build"]); + await $`${yarnCmd} server build`; // Source our environment dotenv.config({ path: `${__dirname}/../.env` }); @@ -48,6 +48,7 @@ runMain(async () => { - database role ${DATABASE_OWNER}`, }, ]); + if (!confirm.CONFIRM) { console.error("Confirmation failed; exiting"); process.exit(1); @@ -125,8 +126,8 @@ runMain(async () => { } await pgPool.end(); - runSync(yarnCmd, ["db", "reset", "--erase"]); - runSync(yarnCmd, ["db", "reset", "--shadow", "--erase"]); + await $`${yarnCmd} db reset --erase`; + await $`${yarnCmd} db reset --shadow --erase`; outro(`\ ✅ Setup success diff --git a/scripts/setup_env.js b/scripts/setup_env.mjs similarity index 94% rename from scripts/setup_env.js rename to scripts/setup_env.mjs index 033a8bd8..cb6c448d 100644 --- a/scripts/setup_env.js +++ b/scripts/setup_env.mjs @@ -1,15 +1,17 @@ #!/usr/bin/env node -const { - yarnCmd, - runMain, + +import inquirer from "inquirer"; +import { $ } from "zx"; + +import { checkGit, outro, - withDotenvUpdater, - updateDotenv, readDotenv, - runSync, -} = require("./_setup_utils"); -const inquirer = require("inquirer"); + runMain, + updateDotenv, + withDotenvUpdater, + yarnCmd, +} from "./_setup_utils.mjs"; runMain(async () => { await checkGit(); @@ -62,7 +64,7 @@ runMain(async () => { ); // And perform setup - runSync(yarnCmd, ["server", "build"]); + await $`${yarnCmd} server build`; if (process.argv[2] === "auto") { // We're advancing automatically diff --git a/scripts/start.js b/scripts/start.js deleted file mode 100755 index 26d8bebd..00000000 --- a/scripts/start.js +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env node -const fs = require("fs"); -const { spawn } = require("child_process"); - -const ENVFILE = `${__dirname}/../.env`; - -if (!fs.existsSync(ENVFILE)) { - console.error("🛠️ Please run 'yarn setup' before running 'yarn start'"); - process.exit(1); -} - -spawn("yarn", ["dev"], { - stdio: "inherit", - env: { - ...process.env, - YARN_SILENT: "1", - npm_config_loglevel: "silent", - }, - shell: true, -}); diff --git a/scripts/start.mjs b/scripts/start.mjs new file mode 100755 index 00000000..414612ce --- /dev/null +++ b/scripts/start.mjs @@ -0,0 +1,22 @@ +#!/usr/bin/env zx + +import { $, fs } from "zx"; + +void (async function () { + try { + const ENVFILE = `${__dirname}/../.env`; + if (!fs.existsSync(ENVFILE)) { + console.error("🛠️ Please run 'yarn setup' before running 'yarn start'"); + await $`exit 1`; + } + + await $`set -a`; + await $`source ${ENVFILE}`; + await $`YARN_SILENT=1`; + await $`npm_config_loglevel="silent"`; + await $`set +a`; + await $`yarn dev`; + } catch (error) { + console.error(error); + } +})(); diff --git a/scripts/test.js b/scripts/test.js deleted file mode 100755 index f9bf6c84..00000000 --- a/scripts/test.js +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env node - -require("@app/config/env"); -const { execSync, spawnSync: rawSpawnSync } = require("child_process"); -const concurrently = require("concurrently"); - -function spawnSync(cmd, args, options) { - const result = rawSpawnSync(cmd, args, { - stdio: ["pipe", "inherit", "inherit"], - env: { - ...process.env, - YARN_SILENT: "1", - npm_config_loglevel: "silent", - }, - shell: true, - ...options, - }); - - const { error, status, signal, stderr, stdout } = result; - - if (error) { - throw error; - } - - if (status || signal) { - if (stdout) { - console.log(stdout.toString("utf8")); - } - if (stderr) { - console.error(stderr.toString("utf8")); - } - if (status) { - throw new Error( - `Process exited with status '${status}' (running '${cmd} ${ - args ? args.join(" ") : "" - }')` - ); - } else { - throw new Error( - `Process exited due to signal '${signal}' (running '${cmd} ${ - args ? args.join(" ") : null - }')` - ); - } - } - - return result; -} - -// Dear graphile-migrate, please treat the test DB as if it were the shadow DB -process.env.SHADOW_DATABASE_URL = process.env.TEST_DATABASE_URL; - -// Signal to graphile-migrate scripts that we're in the tests -process.env.IN_TESTS = "1"; -process.env.NODE_ENV = "test"; - -const cmdArgs = process.argv.slice(2); -const watchMode = cmdArgs.find( - (arg) => arg === "--watch" || arg === "--watchAll" -); -const delayArg = cmdArgs.indexOf("--delay"); -let delaySeconds = null; -if (delayArg > -1) { - delaySeconds = parseFloat(cmdArgs[delayArg + 1]); - if (isNaN(delaySeconds)) { - throw new Error("Did not get a valid delay argument in seconds."); - } - setTimeout(main, delaySeconds * 1000); -} else { - main(); -} - -function main() { - const opts = { - stdio: "inherit", - cwd: process.cwd(), - }; - - // Reset the test database - execSync("yarn db gm reset --shadow --erase", opts); - execSync("yarn db watch --once --shadow", opts); - - if (watchMode) { - // We're in watch mode, so keep watching the `current.yml` file - concurrently( - [ - { - name: "jest", - command: `cross-env NODE_OPTIONS=\"--inspect=9876\" jest -i ${watchMode}`, - prefixColor: "greenBright", - }, - { - name: "testdb", - command: "yarn db watch --shadow", - prefixColor: "blue", - }, - ], - { - killOthers: ["failure"], - } - ); - } else { - // Run once, so just run the tests - const argsWithoutDelayArg = cmdArgs.filter((arg) => arg !== "--delay"); - spawnSync("jest", ["-i", ...argsWithoutDelayArg], opts); - } -} diff --git a/scripts/test.mjs b/scripts/test.mjs new file mode 100755 index 00000000..f2a2f03e --- /dev/null +++ b/scripts/test.mjs @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +import concurrently from "concurrently"; +import { $, sleep } from "zx"; + +require("@app/config/env"); + +// Dear graphile-migrate, please treat the test DB as if it were the shadow DB +process.env.SHADOW_DATABASE_URL = process.env.TEST_DATABASE_URL; + +// Signal to graphile-migrate scripts that we're in the tests +process.env.IN_TESTS = "1"; +process.env.NODE_ENV = "test"; + +const cmdArgs = process.argv.slice(2); +const watchMode = cmdArgs.find( + (arg) => arg === "--watch" || arg === "--watchAll" +); +const delayArg = cmdArgs.indexOf("--delay"); +let delaySeconds = null; + +await $`yarn db gm reset --shadow --erase`; +await $`yarn db watch --once --shadow`; + +if (delayArg > -1) { + delaySeconds = parseFloat(cmdArgs[delayArg + 1]); + console.log("delaySeconds"); + console.log(cmdArgs[delayArg + 1]); + console.log(delaySeconds); + if (isNaN(delaySeconds)) { + throw new Error("Did not get a valid delay argument in seconds."); + } + sleep(delaySeconds * 1000); +} + +if (watchMode) { + // We're in watch mode, so keep watching the `current.yml` file + concurrently( + [ + { + name: "jest", + command: `cross-env NODE_OPTIONS=\"--inspect=9876\" jest -i ${watchMode}`, + prefixColor: "greenBright", + }, + { + name: "testdb", + command: "yarn db watch --shadow", + prefixColor: "blue", + }, + ], + { + killOthers: ["failure"], + } + ); +} else { + const argsWithoutDelayArg = cmdArgs + .filter(([arg]) => arg !== "--delay") + .join(" "); + try { + await $`jest -i ${argsWithoutDelayArg}`; + } catch (err) { + console.error(err); + } +} diff --git a/yarn.lock b/yarn.lock index 784c05d6..3298f0b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2819,6 +2819,13 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/fs-extra@^9.0.12": + version "9.0.12" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" + integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== + dependencies: + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -2931,6 +2938,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== +"@types/minimist@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + "@types/mjml-core@*": version "4.7.0" resolved "https://registry.yarnpkg.com/@types/mjml-core/-/mjml-core-4.7.0.tgz#8fc4510ac7927795be1218042222f3dd98cee433" @@ -2950,6 +2962,14 @@ dependencies: "@types/node" "*" +"@types/node-fetch@^2.5.12": + version "2.5.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" + integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node@*", "@types/node@^15.6.1": version "15.6.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" @@ -2960,6 +2980,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.1.tgz#5e07e0cb2ff793aa7a1b41deae76221e6166049f" integrity sha512-/tpUyFD7meeooTRwl3sYlihx2BrJE7q9XF71EguPFIySj9B7qgnRtHsHTho+0AUm4m1SvWGm6uSncrR94q6Vtw== +"@types/node@^16.6": + version "16.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.5.tgz#96142b243977b03d99c338fdb09241d286102711" + integrity sha512-E7SpxDXoHEpmZ9C1gSqwadhE6zPRtf3g0gJy9Y51DsImnR5TcDs3QEiV/3Q7zOM8LWaZp5Gph71NK6ElVMG1IQ== + "@types/nodemailer@^6.4.2": version "6.4.2" resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.2.tgz#d8ee254c969e6ad83fb9a0a0df3a817406a3fa3b" @@ -3839,6 +3864,11 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array-union@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975" + integrity sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -4722,6 +4752,14 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + change-case-all@1.0.14: version "1.0.14" resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" @@ -6162,7 +6200,7 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -duplexer@^0.1.1: +duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== @@ -6659,6 +6697,19 @@ etag@1.8.1, etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-stream@=3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" @@ -6915,6 +6966,17 @@ fast-glob@^3.1.1: micromatch "^4.0.2" picomatch "^2.2.1" +fast-glob@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -7179,6 +7241,20 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -7409,7 +7485,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -7478,6 +7554,18 @@ globby@11.0.3, globby@^11.0.1, globby@^11.0.2: merge2 "^1.3.0" slash "^3.0.0" +globby@^12.0.1: + version "12.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-12.0.2.tgz#53788b2adf235602ed4cabfea5c70a1139e1ab11" + integrity sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ== + dependencies: + array-union "^3.0.1" + dir-glob "^3.0.1" + fast-glob "^3.2.7" + ignore "^5.1.8" + merge2 "^1.4.1" + slash "^4.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -10006,6 +10094,11 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -10098,7 +10191,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -11880,6 +11973,13 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + dependencies: + through "~2.3" + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -12416,6 +12516,13 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= +ps-tree@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -13824,6 +13931,11 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" @@ -14038,6 +14150,13 @@ split2@^3.0.0, split2@^3.1.1: dependencies: readable-stream "^3.0.0" +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= + dependencies: + through "2" + split@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" @@ -14129,6 +14248,13 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= + dependencies: + duplexer "~0.1.1" + stream-each@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" @@ -14621,7 +14747,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: +through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -15856,6 +15982,23 @@ zen-observable@^0.8.14: resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== +zx@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/zx/-/zx-4.1.1.tgz#8a17ad936507b898a6b0b107f68db133ce13635b" + integrity sha512-KMC3s+Dk2IpAxvpgb0dKzLNE3NuFRz9LIVrJamLTpLtN1S3waiEsaRMYrc3SOJN/tT3V6elkwXg2xozHTeO83g== + dependencies: + "@types/fs-extra" "^9.0.12" + "@types/minimist" "^1.2.2" + "@types/node" "^16.6" + "@types/node-fetch" "^2.5.12" + chalk "^4.1.2" + fs-extra "^10.0.0" + globby "^12.0.1" + minimist "^1.2.5" + node-fetch "^2.6.1" + ps-tree "^1.2.0" + which "^2.0.2" + zxcvbn@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30"