diff --git a/.github/workflows/changed.yml b/.github/workflows/changed.yml new file mode 100644 index 000000000..af2c4d5c4 --- /dev/null +++ b/.github/workflows/changed.yml @@ -0,0 +1,31 @@ +name: Typecheck changed examples + +on: + push: + branches: + - main + pull_request: + +jobs: + typecheck: + if: github.repository == 'remix-run/examples' + runs-on: ubuntu-latest + + steps: + - name: 🛑 Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + + - name: ⬇️ Checkout repo + uses: actions/checkout@v3 + + - name: ⎔ Setup node + uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + cache: "yarn" + + - name: 📥 Install deps + run: yarn --frozen-lockfile + + - name: install, build, typecheck + run: node ./scripts/test.mjs diff --git a/dataloader/app/data.server.ts b/dataloader/app/data.server.ts index 7b0efdbed..6efc79292 100644 --- a/dataloader/app/data.server.ts +++ b/dataloader/app/data.server.ts @@ -1,4 +1,4 @@ -interface User { +export interface User { id: string; email: string; name: string; diff --git a/dataloader/app/loaders/userLoader.ts b/dataloader/app/loaders/userLoader.ts index 5cc506f41..4342f7a44 100644 --- a/dataloader/app/loaders/userLoader.ts +++ b/dataloader/app/loaders/userLoader.ts @@ -1,10 +1,11 @@ +import { DataFunctionArgs } from "@remix-run/node"; import DataLoader from "dataloader"; import { db } from "~/data.server"; export const createUsersByIdLoader = () => new DataLoader(async (ids: Readonly) => { - const users = await db.user.findMany({ + const users = db.user.findMany({ where: { id: { in: ids, @@ -14,3 +15,11 @@ export const createUsersByIdLoader = () => const userMap = new Map(users.map((user) => [user.id, user])); return ids.map((id) => userMap.get(id) ?? null); }); + +export interface DataLoaderArgs extends DataFunctionArgs { + context: { + loaders: { + usersById: ReturnType; + }; + }; +} diff --git a/dataloader/app/routes/users.tsx b/dataloader/app/routes/users.tsx index 62e644ab1..bef3b7ef1 100644 --- a/dataloader/app/routes/users.tsx +++ b/dataloader/app/routes/users.tsx @@ -1,13 +1,14 @@ -import type { LoaderArgs } from "@remix-run/node"; import { json } from "@remix-run/node"; import { Outlet, useLoaderData } from "@remix-run/react"; +import { User } from "~/data.server"; +import { DataLoaderArgs } from "~/loaders/userLoader"; -export const loader = async ({ context }: LoaderArgs) => { +export const loader = async ({ context }: DataLoaderArgs) => { const users = await context.loaders.usersById.loadMany([ "ef3fcb93-0623-4d10-adbf-4dd865d6688c", "2cbad877-2da6-422d-baa6-c6a96a9e085f", ]); - return json({ users }); + return json({ users: users.filter((u): u is User => !!u) }); }; export default function UserNames() { diff --git a/dataloader/app/routes/users/index.tsx b/dataloader/app/routes/users/index.tsx index bdd504e1d..e44b7da55 100644 --- a/dataloader/app/routes/users/index.tsx +++ b/dataloader/app/routes/users/index.tsx @@ -1,8 +1,8 @@ -import type { LoaderArgs } from "@remix-run/node"; import { json } from "@remix-run/node"; import { useLoaderData } from "@remix-run/react"; +import { DataLoaderArgs } from "~/loaders/userLoader"; -export const loader = async ({ context }: LoaderArgs) => { +export const loader = async ({ context }: DataLoaderArgs) => { /* * For demo purposes: * Batching & caching also works with multiple calls to `DataLoader#load` diff --git a/dataloader/package.json b/dataloader/package.json index c38740fb6..c39617844 100644 --- a/dataloader/package.json +++ b/dataloader/package.json @@ -16,14 +16,17 @@ "cross-env": "^7.0.3", "dataloader": "^2.0.0", "express": "^4.17.3", - "morgan": "^1.10.0", "isbot": "^3.6.5", + "morgan": "^1.10.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@remix-run/dev": "*", "@remix-run/eslint-config": "*", + "@types/compression": "1.7.2", + "@types/express": "4.17.15", + "@types/morgan": "1.9.3", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.8", "esbuild-register": "^3.3.2", diff --git a/dataloader/server/index.ts b/dataloader/server/index.ts index 5d7e9249d..479f85758 100644 --- a/dataloader/server/index.ts +++ b/dataloader/server/index.ts @@ -1,11 +1,11 @@ -const path = require("path"); +import path from "path"; -const express = require("express"); -const compression = require("compression"); -const morgan = require("morgan"); -const { createRequestHandler } = require("@remix-run/express"); +import express from "express"; +import compression from "compression"; +import morgan from "morgan"; +import { createRequestHandler } from "@remix-run/express"; -const { createUsersByIdLoader } = require("../app/loaders/userLoader"); +import { createUsersByIdLoader } from "../app/loaders/userLoader"; const MODE = process.env.NODE_ENV; const BUILD_DIR = path.join(process.cwd(), "server/build"); diff --git a/dataloader/tsconfig.json b/dataloader/tsconfig.json index 0700df63b..d3f495c2f 100644 --- a/dataloader/tsconfig.json +++ b/dataloader/tsconfig.json @@ -1,6 +1,8 @@ { "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx", "server/index.ts"], "compilerOptions": { + "allowJs": true, + "forceConsistentCasingInFileNames": true, "lib": ["DOM", "DOM.Iterable", "ES2019"], "isolatedModules": true, "esModuleInterop": true, diff --git a/file-and-cloudinary-upload/app/routes/cloudinary-upload.tsx b/file-and-cloudinary-upload/app/routes/cloudinary-upload.tsx index 8fef5a8c1..31bf8bc05 100644 --- a/file-and-cloudinary-upload/app/routes/cloudinary-upload.tsx +++ b/file-and-cloudinary-upload/app/routes/cloudinary-upload.tsx @@ -33,7 +33,7 @@ export const action = async ({ request }: ActionArgs) => { }; export default function Index() { - const data = useActionData(); + const actionData = useActionData(); return ( <> @@ -44,12 +44,15 @@ export default function Index() { - {data?.error ?

{data.error}

: null} + {actionData && "error" in actionData ?

{actionData.error}

: null} - {data?.imgSrc ? ( + {actionData && "imgSrc" in actionData ? ( <>

uploaded image

- {data.imgDesc + {actionData.imgDesc ) : null} diff --git a/file-and-cloudinary-upload/app/routes/local-upload.tsx b/file-and-cloudinary-upload/app/routes/local-upload.tsx index 467889145..4afa0e1d9 100644 --- a/file-and-cloudinary-upload/app/routes/local-upload.tsx +++ b/file-and-cloudinary-upload/app/routes/local-upload.tsx @@ -26,7 +26,7 @@ export const action = async ({ request }: ActionArgs) => { }; export default function Index() { - const data = useActionData(); + const actionData = useActionData(); return ( <> @@ -34,12 +34,12 @@ export default function Index() { - {data?.error ?

{data.error}

: null} + {actionData && "error" in actionData ?

{actionData.error}

: null} - {data?.imgSrc ? ( + {actionData && "imgSrc" in actionData ? ( <>

uploaded image

- uploaded + uploaded ) : null} diff --git a/file-and-cloudinary-upload/app/utils/utils.server.ts b/file-and-cloudinary-upload/app/utils/utils.server.ts index 0cc958dfc..4cc1714e2 100644 --- a/file-and-cloudinary-upload/app/utils/utils.server.ts +++ b/file-and-cloudinary-upload/app/utils/utils.server.ts @@ -1,4 +1,4 @@ -import cloudinary from "cloudinary"; +import cloudinary, { UploadApiResponse } from "cloudinary"; import { writeAsyncIterableToWritable } from "@remix-run/node"; cloudinary.v2.config({ @@ -8,21 +8,23 @@ cloudinary.v2.config({ }); async function uploadImage(data: AsyncIterable) { - const uploadPromise = new Promise(async (resolve, reject) => { - const uploadStream = cloudinary.v2.uploader.upload_stream( - { - folder: "remix", - }, - (error, result) => { - if (error) { - reject(error); - return; + const uploadPromise = new Promise( + async (resolve, reject) => { + const uploadStream = cloudinary.v2.uploader.upload_stream( + { + folder: "remix", + }, + (error, result) => { + if (error || !result) { + reject(error); + return; + } + resolve(result); } - resolve(result); - } - ); - await writeAsyncIterableToWritable(data, uploadStream); - }); + ); + await writeAsyncIterableToWritable(data, uploadStream); + } + ); return uploadPromise; } diff --git a/package.json b/package.json index f875f0626..8264c25a4 100644 --- a/package.json +++ b/package.json @@ -20,5 +20,11 @@ }, "engines": { "node": ">=14" + }, + "dependencies": { + "@antfu/ni": "^0.18.8", + "@npmcli/package-json": "^3.0.0", + "execa": "^6.1.0", + "fs-extra": "11.1.0" } } diff --git a/pm-app/app/routes/register.tsx b/pm-app/app/routes/register.tsx index f576239ad..09b102216 100644 --- a/pm-app/app/routes/register.tsx +++ b/pm-app/app/routes/register.tsx @@ -125,8 +125,15 @@ export const action = async ({ request }: ActionArgs) => { }; export default function Register() { - const actionData = useActionData() || {}; - const { fieldErrors, fields, formError } = actionData; + const actionData = useActionData(); + let fieldErrors = + actionData && "fieldErrors" in actionData + ? actionData.fieldErrors + : undefined; + let formError = + actionData && "formError" in actionData ? actionData.formError : undefined; + let fields = + actionData && "fields" in actionData ? actionData.fields : undefined; const [searchParams] = useSearchParams(); React.useEffect(() => { @@ -169,7 +176,7 @@ export default function Register() { id="form-error-text" role="alert" > - {actionData.formError} + {formError} ) : null} @@ -194,7 +201,7 @@ export default function Register() { error={fieldErrors?.nameFirst} > - + - + @@ -227,7 +234,10 @@ export default function Register() { error={fieldErrors?.password} > - + diff --git a/pm-app/app/ui/form.tsx b/pm-app/app/ui/form.tsx index 0b07f8596..5a70a36b5 100644 --- a/pm-app/app/ui/form.tsx +++ b/pm-app/app/ui/form.tsx @@ -9,7 +9,7 @@ export function useFieldContext() { return React.useContext(FieldContext); } -const FieldProvider = React.forwardRef< +export const FieldProvider = React.forwardRef< HTMLDivElement, React.PropsWithChildren >(({ children, className, ...ctx }, ref) => { diff --git a/pm-app/package.json b/pm-app/package.json index 2ba250975..920fcadc3 100644 --- a/pm-app/package.json +++ b/pm-app/package.json @@ -2,19 +2,19 @@ "private": true, "sideEffects": false, "scripts": { - "build": "run-s \"build:*\"", "build:css": "npm run generate:css -- --env production", "build:remix": "remix build", + "build": "run-s \"build:*\"", "db:check": "docker ps", "db:reset": "prisma migrate reset --force", "db:start": "docker compose up -d", "db:stop": "docker compose down", "db:update": "prisma migrate dev", "deploy": "flyctl deploy", - "dev": "npm run db:start && pm2-dev pm2.config.js", "dev:css": "npm run generate:css -- --watch", "dev:remix": "remix dev", "dev:server": "node server/index.js", + "dev": "npm run db:start && pm2-dev pm2.config.js", "generate:css": "postcss app/styles --base app/styles --dir app/dist/styles", "start": "node server/index.js", "typecheck": "tsc -b" diff --git a/scripts/test.mjs b/scripts/test.mjs new file mode 100755 index 000000000..f83ed3b5d --- /dev/null +++ b/scripts/test.mjs @@ -0,0 +1,101 @@ +#!/usr/bin/env node + +import path from "node:path"; + +import { execa } from "execa"; +import { detect, getCommand } from "@antfu/ni"; +import PackageJson from "@npmcli/package-json"; +import fse from "fs-extra"; + +const TO_IGNORE = [".github", "scripts", "yarn.lock", "package.json"]; + +const { stderr, stdout, exitCode } = await execa( + "git", + ["--no-pager", "diff", "--name-only", "HEAD~1"], + { cwd: process.cwd() } +); + +if (exitCode !== 0) { + console.error(stderr); + process.exit(exitCode); +} + +const files = stdout.split("\n"); + +const dirs = files.map((f) => f.split("/").at(0)); + +const examples = [...new Set(dirs)].filter((d) => !TO_IGNORE.includes(d)); + +const settled = await Promise.allSettled( + examples.map(async (example) => { + const pkgJson = await PackageJson.load(example); + + /** @type {import('execa').Options} */ + const options = { cwd: example }; + + const detected = await detect({ cwd: example }); + + const install = await getCommand(detected, "install", ["--silent"]); + const installArgs = install.split(" ").slice(1, -1); + const installResult = await execa(detected, installArgs, options); + + if (installResult.exitCode) { + console.error(`Error installing ${example}`); + console.error(installResult.stderr); + return; + } + + const hasPrisma = fse.existsSync( + path.join(example, "prisma", "schema.prisma") + ); + + if (hasPrisma) { + const prismaGenerate = await execa( + "npx", + ["prisma", "generate"], + options + ); + + if (prismaGenerate.exitCode) { + console.error(`Error generating prisma types for ${example}`); + console.error(prismaGenerate.stderr); + return; + } + } + + const build = await getCommand(detected, "run", ["build"]); + const buildArgs = build.split(" ").slice(1); + const buildResult = await execa(detected, buildArgs, options); + + if (buildResult.exitCode) { + console.error(`Error building ${example}`); + console.error(buildResult.stderr); + return; + } + + if (!("typecheck" in pkgJson.content.scripts)) { + pkgJson.update({ + scripts: { + ...pkgJson.content.scripts, + typecheck: "tsc --skipLibCheck", + }, + }); + + await pkgJson.save(); + } + + const typecheck = await getCommand(detected, "run", ["typecheck"]); + const typecheckArgs = typecheck.split(" ").slice(1); + const typecheckResult = await execa(detected, typecheckArgs, options); + + if (typecheckResult.exitCode) { + console.error(`Error typechecking ${example}`); + console.error(typecheckResult.stderr); + return; + } + }) +); + +const rejected = settled.filter((s) => s.status === "rejected"); +rejected.forEach((s) => console.error(s.reason)); +process.exit(rejected.length > 0 ? 1 : 0); diff --git a/yarn.lock b/yarn.lock index a56b4ec3e..28079cce7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,11 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@antfu/ni@^0.18.8": + version "0.18.8" + resolved "https://registry.npmjs.org/@antfu/ni/-/ni-0.18.8.tgz#a0963b8ac07374e6d9ba2b5d81c4d1fc98017c22" + integrity sha512-0m++AudwQq+wWAz/Ax7g+sh/wFW51HHQ6BtPLsuTAsFIzWB/bv/0COwZE7BRS+u0nqMb6Ks6nlk6cY1TpPDwHg== + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" @@ -683,6 +688,13 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@npmcli/package-json@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@npmcli/package-json/-/package-json-3.0.0.tgz#c9219a197e1be8dbf43c4ef8767a72277c0533b6" + integrity sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg== + dependencies: + json-parse-even-better-errors "^3.0.0" + "@pkgr/utils@^2.3.1": version "2.3.1" resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03" @@ -1845,6 +1857,21 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" + integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^3.0.1" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -1944,6 +1971,15 @@ flatted@^3.1.0: resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +fs-extra@11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz#5784b102104433bb0e090f48bfc4a30742c357ed" + integrity sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1998,7 +2034,7 @@ get-package-type@^0.1.0: resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stream@^6.0.0: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -2087,7 +2123,7 @@ globrex@^0.1.2: resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -2148,6 +2184,11 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" + integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== + ignore@^5.1.1, ignore@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" @@ -2327,6 +2368,11 @@ is-stream@^2.0.0: resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -2798,6 +2844,11 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-parse-even-better-errors@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz#2cb2ee33069a78870a0c7e3da560026b89669cf7" + integrity sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2820,6 +2871,15 @@ json5@^2.2.1: resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.2: version "3.3.3" resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" @@ -2962,6 +3022,11 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -3016,6 +3081,13 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -3090,6 +3162,13 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + open@^8.4.0: version "8.4.0" resolved "https://registry.npmjs.org/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" @@ -3188,6 +3267,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -3548,6 +3632,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -3702,6 +3791,11 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + update-browserslist-db@^1.0.9: version "1.0.9" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18"