From bf6bf4ed1862fe491cfb6dc00e0a605b49994afe Mon Sep 17 00:00:00 2001 From: dimaslz Date: Sat, 6 Jan 2024 14:29:40 +0000 Subject: [PATCH] chore(cli): add linter --- package.json | 1 + packages/cli/.eslintrc.cjs | 17 + packages/cli/package.json | 12 +- packages/cli/prebuild.mjs | 35 +- packages/cli/publish.mjs | 240 ++-- packages/cli/src/constants.ts | 2 +- packages/cli/src/generate-proxy-image.test.ts | 796 +++++++------ packages/cli/src/generate-proxy-image.ts | 261 +++-- packages/cli/src/index.ts | 24 +- packages/cli/src/list-container.test.ts | 82 +- packages/cli/src/list-container.ts | 64 +- packages/cli/src/on-create-action.test.ts | 589 +++++----- packages/cli/src/on-create-action.ts | 153 +-- packages/cli/src/on-list-action.test.ts | 70 +- packages/cli/src/on-list-action.ts | 83 +- packages/cli/src/on-remove-action.test.ts | 356 +++--- packages/cli/src/on-remove-action.ts | 87 +- packages/cli/src/on-update-action.test.ts | 316 ++--- packages/cli/src/on-update-action.ts | 63 +- packages/cli/src/templates.ts | 12 +- packages/cli/src/utils/index.ts | 2 +- .../cli/src/utils/validate-domain.test.ts | 90 +- packages/cli/src/utils/validate-domain.ts | 28 +- packages/cli/src/utils/validate-location.ts | 12 +- packages/cli/src/utils/validate-port.test.ts | 87 +- packages/cli/src/utils/validate-port.ts | 32 +- packages/cli/vite.config.ts | 26 +- packages/cli/vitest.config.ts | 22 +- yarn.lock | 1016 ++++++++++++++++- 29 files changed, 2922 insertions(+), 1656 deletions(-) create mode 100644 packages/cli/.eslintrc.cjs diff --git a/package.json b/package.json index 64d26a9..912b5db 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "reset:dependencies": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +", "app:dev": "yarn --cwd=./packages/app dev", "core:build": "yarn --cwd=./packages/core build", + "cli:lint": "yarn --cwd=./packages/cli lint", "cli:build": "yarn --cwd=./packages/cli build", "cli:publish": "yarn --cwd=./packages/cli to-publish", "cli:test": "yarn --cwd=./packages/cli test --reporter=verbose", diff --git a/packages/cli/.eslintrc.cjs b/packages/cli/.eslintrc.cjs new file mode 100644 index 0000000..1a4ecdb --- /dev/null +++ b/packages/cli/.eslintrc.cjs @@ -0,0 +1,17 @@ +// eslint-disable-next-line no-undef +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + env: { node: true, es2020: true }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + ], + plugins: ["simple-import-sort"], + ignorePatterns: ["dist"], + rules: { + "simple-import-sort/imports": "error", + "simple-import-sort/exports": "error", + }, +}; diff --git a/packages/cli/package.json b/packages/cli/package.json index 8694dfd..8447001 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -41,7 +41,8 @@ "local-build": "ncc build src/index.ts -m -o dist", "build": "ncc build src/index.ts -m -o publish/dist", "to-publish": "npx vite-node publish.js", - "test": "vitest" + "test": "vitest", + "lint": "eslint ." }, "dependencies": { "@dimaslz/local-ssl-management-core": "*", @@ -59,10 +60,19 @@ "@types/jest": "^29.5.2", "@types/node": "^20.3.1", "@types/shelljs": "^0.8.12", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", "@vercel/ncc": "^0.36.1", "@vitest/coverage-v8": "^0.32.2", "cpy": "^10.1.0", "cpy-cli": "^4.2.0", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-simple-import-sort": "^10.0.0", + "oxlint": "^0.0.22", + "prettier": "^3.1.1", "jest": "^29.5.0", "rimraf": "^5.0.1", "typescript": "^5.1.3", diff --git a/packages/cli/prebuild.mjs b/packages/cli/prebuild.mjs index f8f967e..6e46a66 100644 --- a/packages/cli/prebuild.mjs +++ b/packages/cli/prebuild.mjs @@ -1,29 +1,28 @@ -import fs from "fs"; import cpy from "cpy"; +import fs from "fs"; import { rimrafSync } from "rimraf"; - const prebuild = async () => { - if (fs.existsSync("dist/.local-ssl-management")) { - await cpy("dist/.local-ssl-management/**/*", ".tmp-local-ssl-management"); - } + if (fs.existsSync("dist/.local-ssl-management")) { + await cpy("dist/.local-ssl-management/**/*", ".tmp-local-ssl-management"); + } - rimrafSync("dist"); + rimrafSync("dist"); - if (fs.existsSync(".tmp-local-ssl-management")) { - fs.mkdirSync("dist", { recursive: true }); - await cpy(".tmp-local-ssl-management/**/*", "dist/.local-ssl-management"); - } + if (fs.existsSync(".tmp-local-ssl-management")) { + fs.mkdirSync("dist", { recursive: true }); + await cpy(".tmp-local-ssl-management/**/*", "dist/.local-ssl-management"); + } - rimrafSync(".tmp-local-ssl-management"); + rimrafSync(".tmp-local-ssl-management"); - if (!fs.existsSync(".local-ssl-management/ssl")) { - fs.mkdirSync("dist/.local-ssl-management/ssl", { recursive: true }); - } -} + if (!fs.existsSync(".local-ssl-management/ssl")) { + fs.mkdirSync("dist/.local-ssl-management/ssl", { recursive: true }); + } +}; if (process.env.CI) { - rimrafSync("dist"); + rimrafSync("dist"); } else { - prebuild(); -} \ No newline at end of file + prebuild(); +} diff --git a/packages/cli/publish.mjs b/packages/cli/publish.mjs index 3da309c..04f7d59 100644 --- a/packages/cli/publish.mjs +++ b/packages/cli/publish.mjs @@ -1,132 +1,136 @@ -import prompts from "prompts"; -import semver from "semver"; import ncc from "@vercel/ncc"; -import fs from "fs"; import cpy from "cpy"; -import shell from "shelljs"; +import fs from "fs"; +import path from "path"; +import prompts from "prompts"; import { rimrafSync } from "rimraf"; +import semver from "semver"; +import shell from "shelljs"; -import packageFile from "./package.json" assert { - type: "json", -}; -import path from "path"; +import packageFile from "./package.json" assert { type: "json" }; const BRANCH = "main"; async function prompt(props, onCancel = null) { - return await prompts(props, { - onCancel: onCancel || (() => { - console.log("\nšŸ›‘ Command release has been canceled.\n") + return await prompts(props, { + onCancel: + onCancel || + (() => { + console.log("\nšŸ›‘ Command release has been canceled.\n"); - shell.exit(1); - }) - }) -}; + shell.exit(1); + }), + }); +} const run = async () => { - await rimrafSync("publish"); - const { value: canRelease } = await prompt({ - type: 'confirm', - name: 'value', - message: 'Are you sure to release now?', - initial: null - }); - - if (!canRelease) process.exit(1); - - const { value: releaseType } = await prompt({ - type: "select", - name: "value", - message: "Set the update type", - choices: [ - { title: 'major', description: '', value: 'major' }, - { title: 'minor', description: '', value: 'minor' }, - { title: 'patch', description: '', value: 'patch' }, - { title: 'premajor', description: '', value: 'premajor' }, - { title: 'preminor', description: '', value: 'preminor' }, - { title: 'prepatch', description: '', value: 'prepatch' }, - { title: 'prerelease', description: '', value: 'prerelease' }, - ], - initial: 0, - }); - - if (!releaseType) process.exit(1); - - const [version, prefix] = packageFile.version.split("-"); - const [type, n] = prefix.split("."); - const newVersion = semver.inc(version, releaseType, type, +n + 1); - - shell.echo(`New version is ${newVersion}`); - - const { value: canCommit } = await prompt({ - type: 'confirm', - name: 'value', - message: 'Do you want to commit changes?', - initial: true - }); - - if (canCommit) { - shell.exec(`git add . && git commit -m "chore(tag): bump version to ${newVersion}"`); - } - - const { value: canTag } = await prompt({ - type: 'confirm', - name: 'value', - message: 'Do you want to tag the package version?', - initial: true - }); - - if (canTag) { - shell.exec(`git add . && git tag ${newVersion} && git push -f --tags origin ${BRANCH}`); - } - - const { value: canPublishPackage } = await prompt({ - type: 'confirm', - name: 'value', - message: 'Do you want to publish the package?', - initial: true - }); - - if (canPublishPackage) { - const pckg = packageFile; - delete pckg.dependencies; - delete pckg.devDependencies; - delete pckg.scripts; - delete pckg.publishConfig; - pckg.version = newVersion; - - if (!fs.existsSync("publish")) { - fs.mkdirSync("publish", { recursive: true }); - } - - if (fs.existsSync("dist/.local-ssl-management")) { - await cpy("dist/.local-ssl-management/**/*", ".tmp-local-ssl-management"); - } - - rimrafSync("dist"); - shell.exec("yarn build"); - - if (fs.existsSync("package.json")) { - fs.writeFileSync("publish/package.json", JSON.stringify(pckg, null, 2)); - } - - if (fs.existsSync(".tmp-local-ssl-management")) { - fs.mkdirSync("dist", { recursive: true }); - await cpy(".tmp-local-ssl-management/**/*", "dist/.local-ssl-management"); - } - - rimrafSync(".tmp-local-ssl-management"); - - if (!fs.existsSync(".local-ssl-management/ssl")) { - fs.mkdirSync("dist/.local-ssl-management/ssl", { recursive: true }); - } - - shell.cd("publish"); - shell.exec(`npm publish --access public`); - shell.cd(".."); - } - - console.log("šŸŽ‰ Done!"); + await rimrafSync("publish"); + const { value: canRelease } = await prompt({ + type: "confirm", + name: "value", + message: "Are you sure to release now?", + initial: null, + }); + + if (!canRelease) process.exit(1); + + const { value: releaseType } = await prompt({ + type: "select", + name: "value", + message: "Set the update type", + choices: [ + { title: "major", description: "", value: "major" }, + { title: "minor", description: "", value: "minor" }, + { title: "patch", description: "", value: "patch" }, + { title: "premajor", description: "", value: "premajor" }, + { title: "preminor", description: "", value: "preminor" }, + { title: "prepatch", description: "", value: "prepatch" }, + { title: "prerelease", description: "", value: "prerelease" }, + ], + initial: 0, + }); + + if (!releaseType) process.exit(1); + + const [version, prefix] = packageFile.version.split("-"); + const [type, n] = prefix.split("."); + const newVersion = semver.inc(version, releaseType, type, +n + 1); + + shell.echo(`New version is ${newVersion}`); + + const { value: canCommit } = await prompt({ + type: "confirm", + name: "value", + message: "Do you want to commit changes?", + initial: true, + }); + + if (canCommit) { + shell.exec( + `git add . && git commit -m "chore(tag): bump version to ${newVersion}"`, + ); + } + + const { value: canTag } = await prompt({ + type: "confirm", + name: "value", + message: "Do you want to tag the package version?", + initial: true, + }); + + if (canTag) { + shell.exec( + `git add . && git tag ${newVersion} && git push -f --tags origin ${BRANCH}`, + ); + } + + const { value: canPublishPackage } = await prompt({ + type: "confirm", + name: "value", + message: "Do you want to publish the package?", + initial: true, + }); + + if (canPublishPackage) { + const pckg = packageFile; + delete pckg.dependencies; + delete pckg.devDependencies; + delete pckg.scripts; + delete pckg.publishConfig; + pckg.version = newVersion; + + if (!fs.existsSync("publish")) { + fs.mkdirSync("publish", { recursive: true }); + } + + if (fs.existsSync("dist/.local-ssl-management")) { + await cpy("dist/.local-ssl-management/**/*", ".tmp-local-ssl-management"); + } + + rimrafSync("dist"); + shell.exec("yarn build"); + + if (fs.existsSync("package.json")) { + fs.writeFileSync("publish/package.json", JSON.stringify(pckg, null, 2)); + } + + if (fs.existsSync(".tmp-local-ssl-management")) { + fs.mkdirSync("dist", { recursive: true }); + await cpy(".tmp-local-ssl-management/**/*", "dist/.local-ssl-management"); + } + + rimrafSync(".tmp-local-ssl-management"); + + if (!fs.existsSync(".local-ssl-management/ssl")) { + fs.mkdirSync("dist/.local-ssl-management/ssl", { recursive: true }); + } + + shell.cd("publish"); + shell.exec(`npm publish --access public`); + shell.cd(".."); + } + + console.log("šŸŽ‰ Done!"); }; run(); diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index f6dc08c..89d5beb 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -1 +1 @@ -export const { pathname: DIRNAME } = new URL(import.meta.url); \ No newline at end of file +export const { pathname: DIRNAME } = new URL(import.meta.url); diff --git a/packages/cli/src/generate-proxy-image.test.ts b/packages/cli/src/generate-proxy-image.test.ts index a46450f..966ea49 100644 --- a/packages/cli/src/generate-proxy-image.test.ts +++ b/packages/cli/src/generate-proxy-image.test.ts @@ -1,49 +1,49 @@ +import { mkcert } from "@dimaslz/local-ssl-management-core"; import fs from "fs"; import shell from "shelljs"; -import { mkcert } from "@dimaslz/local-ssl-management-core"; +import { SpyInstance } from "vitest"; import generateProxyImage from "./generate-proxy-image"; import listContainer from "./list-container"; -import { SpyInstance } from "vitest"; vi.mock("fs"); vi.mock("shelljs"); vi.mock("@dimaslz/local-ssl-management-core", () => ({ - mkcert: vi.fn(), - getLocalIP: vi.fn(() => "192.168.0.0"), + mkcert: vi.fn(), + getLocalIP: vi.fn(() => "192.168.0.0"), })); vi.mock("./list-container"); vi.mock("path", () => ({ - default: { - resolve: () => "/root/path" - } + default: { + resolve: () => "/root/path", + }, })); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); describe("Generate proxy image", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe("single service", () => { - test("does not exists localhost certs", () => { - fs.existsSync = vi.fn(() => false); - - generateProxyImage([]); - - expect(fs.existsSync).toBeCalledTimes(2); - expect(mkcert).toBeCalled(); - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("single service", () => { + test("does not exists localhost certs", () => { + fs.existsSync = vi.fn(() => false); + + generateProxyImage([]); + + expect(fs.existsSync).toBeCalledTimes(2); + expect(mkcert).toBeCalled(); + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -77,12 +77,12 @@ http { } \t\t -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -101,70 +101,64 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(1); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(1); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - expect(shell.echo).nthCalledWith( - 2, - "\ndomain app running\n" - ); - }); - - test("create domain config succesful (localhost certs does not exists)", () => { - vi.spyOn(fs, "existsSync").mockImplementation((v) => { - if (/localhost-cert.pem$/.test(String(v))) { - return false; - } - - if (/demo.com-.*.pem$/.test(String(v))) { - return true; - } - - return false; - }); - - (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation((v) => v); - - generateProxyImage([ - { - "id": "485b5a34-f0c3-4472-8308-6bcc0a485527", - "domain": "demo.com", - "port": "4000", - "location": "/" - } - ]); - - expect(fs.existsSync).toBeCalledTimes(4); - - expect(mkcert).toBeCalledTimes(1); - expect(mkcert).nthCalledWith( - 1, - "localhost", - "/root/path/.local-ssl-management/ssl", - ); - - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + expect(shell.echo).nthCalledWith(2, "\ndomain app running\n"); + }); + + test("create domain config succesful (localhost certs does not exists)", () => { + vi.spyOn(fs, "existsSync").mockImplementation((v) => { + if (/localhost-cert.pem$/.test(String(v))) { + return false; + } + + if (/demo.com-.*.pem$/.test(String(v))) { + return true; + } + + return false; + }); + + (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation((v) => v); + + generateProxyImage([ + { + id: "485b5a34-f0c3-4472-8308-6bcc0a485527", + domain: "demo.com", + port: "4000", + location: "/", + }, + ]); + + expect(fs.existsSync).toBeCalledTimes(4); + + expect(mkcert).toBeCalledTimes(1); + expect(mkcert).nthCalledWith( + 1, + "localhost", + "/root/path/.local-ssl-management/ssl", + ); + + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -215,7 +209,7 @@ http { location / { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -237,12 +231,12 @@ http { expires off; } } -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -262,86 +256,83 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(2); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(2); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - - expect(shell.exec).nthCalledWith( - 2, - "curl -s -o /dev/null -w \"%{http_code}\" https://demo.com", - { silent: true } - ); - - expect(shell.echo).nthCalledWith( - 2, - ` + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + + expect(shell.exec).nthCalledWith( + 2, + 'curl -s -o /dev/null -w "%{http_code}" https://demo.com', + { silent: true }, + ); + + expect(shell.echo).nthCalledWith( + 2, + ` domain app running -https://demo.com āŒ${' '} -` - ); - }); - - test("create domain config succesful (domain certs does not exists)", () => { - vi.spyOn(shell, "exec").mockImplementation(() => { - return { status: 200 } - }) - vi.spyOn(fs, "existsSync").mockImplementation((v) => { - if (/localhost-cert.pem$/.test(String(v))) { - return false; - } - - if (/demo.com-.*.pem$/.test(String(v))) { - return false; - } - - return false; - }); - - generateProxyImage([ - { - "id": "485b5a34-f0c3-4472-8308-6bcc0a485527", - "domain": "demo.com", - "port": "4000", - "location": "/" - } - ]); - - expect(fs.existsSync).toBeCalledTimes(4); - - expect(mkcert).toBeCalledTimes(2); - expect(mkcert).nthCalledWith( - 1, - "localhost", - "/root/path/.local-ssl-management/ssl", - ); - expect(mkcert).nthCalledWith( - 2, - "demo.com", - "/root/path/.local-ssl-management/ssl", - ); - - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; +https://demo.com āŒ${" "} +`, + ); + }); + + test("create domain config succesful (domain certs does not exists)", () => { + vi.spyOn(shell, "exec").mockImplementation(() => { + return { status: 200 }; + }); + vi.spyOn(fs, "existsSync").mockImplementation((v) => { + if (/localhost-cert.pem$/.test(String(v))) { + return false; + } + + if (/demo.com-.*.pem$/.test(String(v))) { + return false; + } + + return false; + }); + + generateProxyImage([ + { + id: "485b5a34-f0c3-4472-8308-6bcc0a485527", + domain: "demo.com", + port: "4000", + location: "/", + }, + ]); + + expect(fs.existsSync).toBeCalledTimes(4); + + expect(mkcert).toBeCalledTimes(2); + expect(mkcert).nthCalledWith( + 1, + "localhost", + "/root/path/.local-ssl-management/ssl", + ); + expect(mkcert).nthCalledWith( + 2, + "demo.com", + "/root/path/.local-ssl-management/ssl", + ); + + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -392,7 +383,7 @@ http { location / { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -414,12 +405,12 @@ http { expires off; } } -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -439,56 +430,53 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(2); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(2); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - - expect(shell.exec).nthCalledWith( - 2, - "curl -s -o /dev/null -w \"%{http_code}\" https://demo.com", - { silent: true } - ); - - expect(shell.echo).nthCalledWith( - 2, - ` + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + + expect(shell.exec).nthCalledWith( + 2, + 'curl -s -o /dev/null -w "%{http_code}" https://demo.com', + { silent: true }, + ); + + expect(shell.echo).nthCalledWith( + 2, + ` domain app running -https://demo.com āŒ${' '} -` - ); - }); - }); - - describe("multiple service", () => { - test("does not exists localhost certs", () => { - fs.existsSync = vi.fn(() => false); - - generateProxyImage([]); - - expect(fs.existsSync).toBeCalledTimes(2); - expect(mkcert).toBeCalled(); - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; +https://demo.com āŒ${" "} +`, + ); + }); + }); + + describe("multiple service", () => { + test("does not exists localhost certs", () => { + fs.existsSync = vi.fn(() => false); + + generateProxyImage([]); + + expect(fs.existsSync).toBeCalledTimes(2); + expect(mkcert).toBeCalled(); + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -522,12 +510,12 @@ http { } \t\t -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -546,70 +534,64 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(1); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(1); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - expect(shell.echo).nthCalledWith( - 2, - "\ndomain app running\n" - ); - }); - - test("create domain config succesful (localhost certs does not exists)", () => { - vi.spyOn(fs, "existsSync").mockImplementation((v) => { - if (/localhost-cert.pem$/.test(String(v))) { - return false; - } - - if (/demo.com-.*.pem$/.test(String(v))) { - return true; - } - - return false; - }); - - (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation((v) => v); - - generateProxyImage([ - { - "id": "485b5a34-f0c3-4472-8308-6bcc0a485527", - "domain": "demo.com", - "port": "4000,3000", - "location": "/,/app-name" - } - ]); - - expect(fs.existsSync).toBeCalledTimes(4); - - expect(mkcert).toBeCalledTimes(1); - expect(mkcert).nthCalledWith( - 1, - "localhost", - "/root/path/.local-ssl-management/ssl", - ); - - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + expect(shell.echo).nthCalledWith(2, "\ndomain app running\n"); + }); + + test("create domain config succesful (localhost certs does not exists)", () => { + vi.spyOn(fs, "existsSync").mockImplementation((v) => { + if (/localhost-cert.pem$/.test(String(v))) { + return false; + } + + if (/demo.com-.*.pem$/.test(String(v))) { + return true; + } + + return false; + }); + + (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation((v) => v); + + generateProxyImage([ + { + id: "485b5a34-f0c3-4472-8308-6bcc0a485527", + domain: "demo.com", + port: "4000,3000", + location: "/,/app-name", + }, + ]); + + expect(fs.existsSync).toBeCalledTimes(4); + + expect(mkcert).toBeCalledTimes(1); + expect(mkcert).nthCalledWith( + 1, + "localhost", + "/root/path/.local-ssl-management/ssl", + ); + + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -660,7 +642,7 @@ http { location / { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -684,7 +666,7 @@ http { location /app-name { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -706,12 +688,12 @@ location /app-name { expires off; } } -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -731,86 +713,83 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(2); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(2); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - - expect(shell.exec).nthCalledWith( - 2, - "curl -s -o /dev/null -w \"%{http_code}\" https://demo.com", - { silent: true } - ); - - expect(shell.echo).nthCalledWith( - 2, - ` + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + + expect(shell.exec).nthCalledWith( + 2, + 'curl -s -o /dev/null -w "%{http_code}" https://demo.com', + { silent: true }, + ); + + expect(shell.echo).nthCalledWith( + 2, + ` domain app running -https://demo.com āŒ${' '} -` - ); - }); - - test("create domain config succesful (domain certs does not exists)", () => { - vi.spyOn(shell, "exec").mockImplementation(() => { - return { status: 200 } - }) - vi.spyOn(fs, "existsSync").mockImplementation((v) => { - if (/localhost-cert.pem$/.test(String(v))) { - return false; - } - - if (/demo.com-.*.pem$/.test(String(v))) { - return false; - } - - return false; - }); - - generateProxyImage([ - { - "id": "485b5a34-f0c3-4472-8308-6bcc0a485527", - "domain": "demo.com", - "port": "4000,3000", - "location": "/,/app-name" - } - ]); - - expect(fs.existsSync).toBeCalledTimes(4); - - expect(mkcert).toBeCalledTimes(2); - expect(mkcert).nthCalledWith( - 1, - "localhost", - "/root/path/.local-ssl-management/ssl", - ); - expect(mkcert).nthCalledWith( - 2, - "demo.com", - "/root/path/.local-ssl-management/ssl", - ); - - expect(fs.writeFileSync).toBeCalledTimes(2); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 1, - "/root/path/.local-ssl-management/nginx.conf", - `user nginx; +https://demo.com āŒ${" "} +`, + ); + }); + + test("create domain config succesful (domain certs does not exists)", () => { + vi.spyOn(shell, "exec").mockImplementation(() => { + return { status: 200 }; + }); + vi.spyOn(fs, "existsSync").mockImplementation((v) => { + if (/localhost-cert.pem$/.test(String(v))) { + return false; + } + + if (/demo.com-.*.pem$/.test(String(v))) { + return false; + } + + return false; + }); + + generateProxyImage([ + { + id: "485b5a34-f0c3-4472-8308-6bcc0a485527", + domain: "demo.com", + port: "4000,3000", + location: "/,/app-name", + }, + ]); + + expect(fs.existsSync).toBeCalledTimes(4); + + expect(mkcert).toBeCalledTimes(2); + expect(mkcert).nthCalledWith( + 1, + "localhost", + "/root/path/.local-ssl-management/ssl", + ); + expect(mkcert).nthCalledWith( + 2, + "demo.com", + "/root/path/.local-ssl-management/ssl", + ); + + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/nginx.conf", + `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -861,7 +840,7 @@ http { location / { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -885,7 +864,7 @@ http { location /app-name { gzip on; - gzip_disable \"msie6\"; + gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; @@ -907,12 +886,12 @@ location /app-name { expires off; } } -}` - ); - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - "/root/path/.local-ssl-management/Dockerfile", - `FROM nginx +}`, + ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/Dockerfile", + `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -932,40 +911,37 @@ COPY nginx.conf /etc/nginx/ EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"]` - ); +CMD ["nginx", "-g", "daemon off;"]`, + ); - expect(shell.exec).toBeCalledTimes(2); - expect(shell.exec).toHaveBeenNthCalledWith( - 1, - `NAME=local-ssl-management && \ + expect(shell.exec).toBeCalledTimes(2); + expect(shell.exec).toHaveBeenNthCalledWith( + 1, + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME /root/path/.local-ssl-management && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - expect(listContainer).toBeCalled(); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\nSSL proxy running\n" - ); - - expect(shell.exec).nthCalledWith( - 2, - "curl -s -o /dev/null -w \"%{http_code}\" https://demo.com", - { silent: true } - ); - - expect(shell.echo).nthCalledWith( - 2, - ` + { silent: true }, + ); + expect(listContainer).toBeCalled(); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith(1, "\nSSL proxy running\n"); + + expect(shell.exec).nthCalledWith( + 2, + 'curl -s -o /dev/null -w "%{http_code}" https://demo.com', + { silent: true }, + ); + + expect(shell.echo).nthCalledWith( + 2, + ` domain app running -https://demo.com āŒ${' '} -` - ); - }); - }); +https://demo.com āŒ${" "} +`, + ); + }); + }); }); diff --git a/packages/cli/src/generate-proxy-image.ts b/packages/cli/src/generate-proxy-image.ts index e150153..ced42a7 100644 --- a/packages/cli/src/generate-proxy-image.ts +++ b/packages/cli/src/generate-proxy-image.ts @@ -1,14 +1,13 @@ -import fs from "fs"; -import shell from "shelljs"; -import path from "path"; - import type { Config } from "@dimaslz/local-ssl-management-core"; import { getLocalIP, mkcert } from "@dimaslz/local-ssl-management-core"; - -import Templates from "./templates"; -import listContainer from "./list-container"; import chalk from "chalk"; import Table from "cli-table"; +import fs from "fs"; +import path from "path"; +import shell from "shelljs"; + +import listContainer from "./list-container"; +import Templates from "./templates"; const LOCAL_IP = getLocalIP(); const distPath = path.resolve(__dirname, "./"); @@ -16,115 +15,147 @@ const rootPath = `${distPath}/.local-ssl-management`; const sslPath = `${rootPath}/ssl`; const generateProxyImage = (config: Config[]) => { - const localhostCertExists = fs.existsSync(sslPath + "/localhost-cert.pem"); - const localhostKeyExists = fs.existsSync(sslPath + "/localhost-key.pem"); - - if (!localhostCertExists || !localhostKeyExists) { - mkcert("localhost", sslPath); - } - - const certsUrl: { cert: string; key: string; }[] = []; - - const serverConfigs: string[] = config.map((c: Config) => { - const nginxConfServerTpl: string = Templates.nginxConfServer || ""; - - const multipleDomains = c.domain.split(",").length > 1; - const domain = multipleDomains ? c.domain.split(",").join(" ") : c.domain.trim(); - const certName = multipleDomains ? c.domain.split(",").join("_") : c.domain.trim(); - - const certFileExists = fs.existsSync(`${sslPath}/${certName}-cert.pem`); - const keyFileExists = fs.existsSync(`${sslPath}/${certName}-key.pem`); - const shouldCreateCerts = !certFileExists || !keyFileExists; - - if (shouldCreateCerts) { - mkcert(domain, sslPath); - } - - certsUrl.push({ - cert: `ssl/${certName}-cert.pem`, - key: `ssl/${certName}-key.pem` - }); - - const nginxLocationTpl: string = Templates.nginxLocation; - - // setup location - let locationConfigs = c.location.split(",").map((locationConfig) => { - return nginxLocationTpl - .replace("%LOCATION%", locationConfig) - .replace("%LOCAL_IP%", LOCAL_IP) - }).join("\n\n"); - - // setup ports - c.port.split(",").forEach((port) => { - locationConfigs = locationConfigs.replace("%PORT%", String(port)); - }); - - return nginxConfServerTpl - .replace(/\%APP_DOMAIN\%/g, certName) - .replace("%SERVER_NAME%", c.domain.split(",").map(i => i.trim()).join(' ')) - .replace("#--server-location--#", locationConfigs); - }); - - const nginxConfTpl = Templates.nginxConf; - const nginxConf = nginxConfTpl - .replace(/\t\t#--server-config--#/, `\t\t${serverConfigs.join("\n")}`); - - // console.log("nginxConf", nginxConf) - const nginxConfDest = `${rootPath}/nginx.conf`; - fs.writeFileSync(nginxConfDest, nginxConf); - - const dockerfileContent = Templates.dockerfile; - const dockerfileDest = `${rootPath}/Dockerfile`; - fs.writeFileSync( - dockerfileDest, - dockerfileContent.replace( - "#-certs-#", - certsUrl.map((d: { cert: string; key: string; }) => { - return `COPY ${d.key} /etc/nginx/ -COPY ${d.cert} /etc/nginx/` - }).join("\n\n") - ).replace(/#-main-path-#/g, "") - ); - - shell.exec( - `NAME=local-ssl-management && \ + const localhostCertExists = fs.existsSync(sslPath + "/localhost-cert.pem"); + const localhostKeyExists = fs.existsSync(sslPath + "/localhost-key.pem"); + + if (!localhostCertExists || !localhostKeyExists) { + mkcert("localhost", sslPath); + } + + const certsUrl: { cert: string; key: string }[] = []; + + const serverConfigs: string[] = config.map((c: Config) => { + const nginxConfServerTpl: string = Templates.nginxConfServer || ""; + + const multipleDomains = c.domain.split(",").length > 1; + const domain = multipleDomains + ? c.domain.split(",").join(" ") + : c.domain.trim(); + const certName = multipleDomains + ? c.domain.split(",").join("_") + : c.domain.trim(); + + const certFileExists = fs.existsSync(`${sslPath}/${certName}-cert.pem`); + const keyFileExists = fs.existsSync(`${sslPath}/${certName}-key.pem`); + const shouldCreateCerts = !certFileExists || !keyFileExists; + + if (shouldCreateCerts) { + mkcert(domain, sslPath); + } + + certsUrl.push({ + cert: `ssl/${certName}-cert.pem`, + key: `ssl/${certName}-key.pem`, + }); + + const nginxLocationTpl: string = Templates.nginxLocation; + + // setup location + let locationConfigs = c.location + .split(",") + .map((locationConfig) => { + return nginxLocationTpl + .replace("%LOCATION%", locationConfig) + .replace("%LOCAL_IP%", LOCAL_IP); + }) + .join("\n\n"); + + // setup ports + c.port.split(",").forEach((port) => { + locationConfigs = locationConfigs.replace("%PORT%", String(port)); + }); + + return nginxConfServerTpl + .replace(/%APP_DOMAIN%/g, certName) + .replace( + "%SERVER_NAME%", + c.domain + .split(",") + .map((i) => i.trim()) + .join(" "), + ) + .replace("#--server-location--#", locationConfigs); + }); + + const nginxConfTpl = Templates.nginxConf; + const nginxConf = nginxConfTpl.replace( + /\t\t#--server-config--#/, + `\t\t${serverConfigs.join("\n")}`, + ); + + // console.log("nginxConf", nginxConf) + const nginxConfDest = `${rootPath}/nginx.conf`; + fs.writeFileSync(nginxConfDest, nginxConf); + + const dockerfileContent = Templates.dockerfile; + const dockerfileDest = `${rootPath}/Dockerfile`; + fs.writeFileSync( + dockerfileDest, + dockerfileContent + .replace( + "#-certs-#", + certsUrl + .map((d: { cert: string; key: string }) => { + return `COPY ${d.key} /etc/nginx/ +COPY ${d.cert} /etc/nginx/`; + }) + .join("\n\n"), + ) + .replace(/#-main-path-#/g, ""), + ); + + shell.exec( + `NAME=local-ssl-management && \ docker rm -f $NAME && \ docker rmi -f $NAME && \ docker build --no-cache -t $NAME ${rootPath} && \ docker run --name $NAME -p 80:80 -p 443:443 -d $NAME`, - { silent: true } - ); - - listContainer(); - - shell.echo(chalk.green("\nSSL proxy running\n")); - - - const tablePing = new Table({ - head: ["domain", "app running"], - chars: { - 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '' - , 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '' - , 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '' - , 'right': '', 'right-mid': '', 'middle': ' ' - }, - style: { 'padding-left': 0, 'padding-right': 0 }, - }); - - config.forEach((c: Config) => { - c.domain.split(",").map(d => d.trim()).forEach((domain) => { - const curl = `curl -s -o /dev/null -w "%{http_code}" https://${domain}`; - const status = shell.exec(curl, { silent: true }).stdout; - - if (status === "200") { - tablePing.push([`https://${domain}`, "āœ…"]); - } else { - tablePing.push([`https://${domain}`, "āŒ"]); - } - }); - }); - - shell.echo(`\n${tablePing.toString()}\n`); -} - -export default generateProxyImage; \ No newline at end of file + { silent: true }, + ); + + listContainer(); + + shell.echo(chalk.green("\nSSL proxy running\n")); + + const tablePing = new Table({ + head: ["domain", "app running"], + chars: { + top: "", + "top-mid": "", + "top-left": "", + "top-right": "", + bottom: "", + "bottom-mid": "", + "bottom-left": "", + "bottom-right": "", + left: "", + "left-mid": "", + mid: "", + "mid-mid": "", + right: "", + "right-mid": "", + middle: " ", + }, + style: { "padding-left": 0, "padding-right": 0 }, + }); + + config.forEach((c: Config) => { + c.domain + .split(",") + .map((d) => d.trim()) + .forEach((domain) => { + const curl = `curl -s -o /dev/null -w "%{http_code}" https://${domain}`; + const status = shell.exec(curl, { silent: true }).stdout; + + if (status === "200") { + tablePing.push([`https://${domain}`, "āœ…"]); + } else { + tablePing.push([`https://${domain}`, "āŒ"]); + } + }); + }); + + shell.echo(`\n${tablePing.toString()}\n`); +}; + +export default generateProxyImage; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index f31b1a4..fd81cac 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,10 +1,10 @@ #! /usr/bin/env node +import { dockerExists, mkcertExists } from "@dimaslz/local-ssl-management-core"; +import { Command } from "commander"; import fs from "fs"; import path from "path"; -import { Command } from 'commander'; -import { dockerExists, mkcertExists } from "@dimaslz/local-ssl-management-core"; import onCreateAction from "./on-create-action"; import onListAction from "./on-list-action"; import onRemoveAction from "./on-remove-action"; @@ -16,11 +16,11 @@ const createBaseFolders = () => { const sslPath = `${rootPath}/ssl`; if (!fs.existsSync(rootPath)) { - fs.mkdirSync(rootPath, { recursive: true }) + fs.mkdirSync(rootPath, { recursive: true }); } if (!fs.existsSync(sslPath)) { - fs.mkdirSync(sslPath, { recursive: true }) + fs.mkdirSync(sslPath, { recursive: true }); } const configPath = `${rootPath}/config.json`; @@ -28,7 +28,7 @@ const createBaseFolders = () => { if (!fs.existsSync(configPath)) { fs.writeFileSync(configPath, "[]"); } -} +}; const cli = () => { createBaseFolders(); @@ -42,13 +42,13 @@ const cli = () => { .command("create ") .description("Create domain") .option("-p, --port ", "Port where is running the application") - .option("-l, --location ", "Location where nginx will serve the application. By default is \"/\"") + .option( + "-l, --location ", + 'Location where nginx will serve the application. By default is "/"', + ) .action(onCreateAction); - program - .command("list") - .description("List domains") - .action(onListAction); + program.command("list").description("List domains").action(onListAction); program .command("update ") @@ -62,6 +62,6 @@ const cli = () => { .action(onRemoveAction); program.parse(); -} +}; -cli(); \ No newline at end of file +cli(); diff --git a/packages/cli/src/list-container.test.ts b/packages/cli/src/list-container.test.ts index d58f37e..f277d7b 100644 --- a/packages/cli/src/list-container.test.ts +++ b/packages/cli/src/list-container.test.ts @@ -1,60 +1,70 @@ import shell from "shelljs"; +import { SpyInstance } from "vitest"; import listContainer from "./list-container"; -import { SpyInstance } from "vitest"; vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); vi.mock("shelljs"); - describe("List container", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe("success", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); - test("commmand found local-ssl-management container running", async () => { - (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation(() => { - return { - stdout: "XXXXXXXXXXXX | local-ssl-management | 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp" - }; - }); + describe("success", () => { + test("commmand found local-ssl-management container running", async () => { + (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation(() => { + return { + stdout: + "XXXXXXXXXXXX | local-ssl-management | 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp", + }; + }); - listContainer(); + listContainer(); - expect(shell.echo).toHaveBeenCalledTimes(2); + expect(shell.echo).toHaveBeenCalledTimes(2); - expect(shell.echo).toHaveBeenNthCalledWith(1, `\nThe local ssl proxy is running.\n - ā„¹ļø The local ssl proxy is running. Keep it mind that it is important to the local domains that works through HTTPS.\n`); - expect(shell.echo).toHaveBeenNthCalledWith(2, ` + expect(shell.echo).toHaveBeenNthCalledWith( + 1, + `\nThe local ssl proxy is running.\n + ā„¹ļø The local ssl proxy is running. Keep it mind that it is important to the local domains that works through HTTPS.\n`, + ); + expect(shell.echo).toHaveBeenNthCalledWith( + 2, + ` ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā”‚ container id ā”‚ container image ā”‚ port ā”‚ ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ ā”‚ XXXXXXXXXXXX ā”‚ local-ssl-management ā”‚ 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp ā”‚ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ -`); - }); - }); +`, + ); + }); + }); - describe("failure", () => { - test("some error happen", () => { - (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation(() => ({ - stdout: "XXXXXXXXXXXX | something | 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp" - })); + describe("failure", () => { + test("some error happen", () => { + (vi.spyOn(shell, "exec") as SpyInstance).mockImplementation(() => ({ + stdout: + "XXXXXXXXXXXX | something | 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp", + })); - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); - expect(() => { listContainer(); }).toThrow(); + expect(() => { + listContainer(); + }).toThrow(); - expect(shell.echo).toHaveBeenCalled(); - expect(shell.exit).toHaveBeenCalled(); - }); - }); + expect(shell.echo).toHaveBeenCalled(); + expect(shell.exit).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/cli/src/list-container.ts b/packages/cli/src/list-container.ts index be72222..72820e6 100644 --- a/packages/cli/src/list-container.ts +++ b/packages/cli/src/list-container.ts @@ -1,33 +1,43 @@ +import chalk from "chalk"; import Table from "cli-table"; import shell from "shelljs"; -import chalk from "chalk"; const listContainer = () => { - const containersList = shell.exec( - "docker ps --format '{{.ID}} | {{.Names}} | {{.Ports}}'", - { silent: true } - ).stdout; - - const table = new Table({ - head: ["container id", "container image", "port"], - }); - - const containerData = containersList.split("\n").find((line) => /local-ssl-management/.test(line)) || ""; - - if (!containerData) { - shell.echo(chalk.red("[Error] - Something have been failure. Contact with the author.")); - shell.exit(1); - - } - - const [containerId, containerName, ports] = containerData.split("|").map(i => i.trim()); - table.push([containerId, containerName, ports]); - - shell.echo(chalk.green( - `\nThe local ssl proxy is running.\n - ā„¹ļø The local ssl proxy is running. Keep it mind that it is important to the local domains that works through HTTPS.\n` - )); - shell.echo(`\n${table.toString()}\n`); + const containersList = shell.exec( + "docker ps --format '{{.ID}} | {{.Names}} | {{.Ports}}'", + { silent: true }, + ).stdout; + + const table = new Table({ + head: ["container id", "container image", "port"], + }); + + const containerData = + containersList + .split("\n") + .find((line) => /local-ssl-management/.test(line)) || ""; + + if (!containerData) { + shell.echo( + chalk.red( + "[Error] - Something have been failure. Contact with the author.", + ), + ); + shell.exit(1); + } + + const [containerId, containerName, ports] = containerData + .split("|") + .map((i) => i.trim()); + table.push([containerId, containerName, ports]); + + shell.echo( + chalk.green( + `\nThe local ssl proxy is running.\n + ā„¹ļø The local ssl proxy is running. Keep it mind that it is important to the local domains that works through HTTPS.\n`, + ), + ); + shell.echo(`\n${table.toString()}\n`); }; -export default listContainer; \ No newline at end of file +export default listContainer; diff --git a/packages/cli/src/on-create-action.test.ts b/packages/cli/src/on-create-action.test.ts index 2599a0a..4b151a2 100644 --- a/packages/cli/src/on-create-action.test.ts +++ b/packages/cli/src/on-create-action.test.ts @@ -1,282 +1,337 @@ +import crypto from "crypto"; import fs from "fs"; -import { SpyInstance } from "vitest"; import shell, { ShellString } from "shelljs"; -import crypto from "crypto"; +import { SpyInstance } from "vitest"; import onCreateAction from "./on-create-action"; vi.mock("shelljs"); vi.mock("./list-container"); vi.mock("@dimaslz/local-ssl-management-core", async () => { - return { - getLocalIP: () => "11.22.33.445", - mkcert: vi.fn(), - } + return { + getLocalIP: () => "11.22.33.445", + mkcert: vi.fn(), + }; }); vi.mock("fs"); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); describe("On create action", () => { - - describe("failures", () => { - beforeEach(() => { - vi.spyOn(shell, 'echo').mockImplementation((v) => ShellString(v)); - vi.spyOn(shell, 'exit').mockImplementation(() => Promise.resolve(1 as never)); - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - }); - - test("can not create with invalid domain", () => { - const domain = "wrong.domain"; - const port = 3000; - - expect(() => { onCreateAction(domain, { port }); }).toThrow(); - - expect(shell.echo).toHaveBeenCalledWith("\n[Error] - Domain (https://wrong.domain)format is not valid\n"); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - - test("can not create with invalid port", () => { - const domain = "some-domain.com"; - const port = 666; - - expect(() => { onCreateAction(domain, { port }); }).toThrow(); - - expect(shell.echo).toHaveBeenCalledWith("\n[Error] - Port (--port ) should be into the range 1025 to 65535\n"); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - }); - - describe("success", () => { - beforeEach(() => { - vi.clearAllMocks(); - - vi.spyOn(fs, "mkdirSync"); - (vi.spyOn(fs, "readdirSync") as SpyInstance).mockImplementation(() => ([ - "some-domain.com-cert.pem", - "some-domain.com-key.pem", - ])); - vi.spyOn(fs, "existsSync").mockReturnValue(true); - vi.spyOn(shell, "exec").mockImplementation(() => { - return { stdout: "200" } - }) - }); - - describe("double service", () => { - - test("domain config created sucessfully (double location)", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "a5051812-e151-4ca3-b9b6-b86f6fb05817", - "domain": "some-domain.com", - "port": "3000", - "location": "/" - }, - ], null, 2)); - - crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); - - const domain = "some-domain.com"; - const port = 3000; - const location = "/lala"; - - onCreateAction(domain, { port, location }); - - expect(fs.readFileSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.local-ssl-management\/config.json/), - { encoding: "utf8" } - ); - expect(fs.existsSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/ssl/), - ); - expect(fs.mkdirSync).not.toHaveBeenCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledTimes(3) - expect(fs.writeFileSync).toHaveBeenNthCalledWith(3, - expect.stringMatching(/.local-ssl-management\/config.json/i), - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": "3000,3000", - "location": "/,/lala" - } - ], null, 2) - ); - }); - - test("domain config created sucessfully (double location with different port)", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "a5051812-e151-4ca3-b9b6-b86f6fb05817", - "domain": "some-domain.com", - "port": "3000", - "location": "/" - }, - ], null, 2)); - - crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); - - const domain = "some-domain.com"; - const port = 4000; - const location = "/lala"; - - onCreateAction(domain, { port, location }); - - expect(fs.readFileSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.local-ssl-management\/config.json/), - { encoding: "utf8" } - ); - expect(fs.existsSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/ssl/), - ); - expect(fs.mkdirSync).not.toHaveBeenCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledTimes(3) - expect(fs.writeFileSync).toHaveBeenNthCalledWith(3, - expect.stringMatching(/.local-ssl-management\/config.json/i), - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": "3000,4000", - "location": "/,/lala" - } - ], null, 2) - ); - }); - }); - - describe("single service", () => { - - test("domain config created sucessfully", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - - crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); - - const domain = "some-domain.com"; - const port = "3000"; - - onCreateAction(domain, { port }); - - expect(fs.readFileSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.local-ssl-management\/config.json/), - { encoding: "utf8" } - ); - expect(fs.existsSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/ssl/), - ); - expect(fs.mkdirSync).not.toHaveBeenCalled(); - - expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 3, - expect.stringMatching(/.local-ssl-management\/config.json/), - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": "3000", - "location": "/" - } - ], null, 2) - ); - }); - - test("double domain config created sucessfully", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - - crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); - - const domain = "some-domain.com,some-domain.es"; - const port = "3000"; - - onCreateAction(domain, { port }); - - expect(fs.readFileSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.local-ssl-management\/config.json/), - { encoding: "utf8" } - ); - expect(fs.existsSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/ssl/), - ); - expect(fs.mkdirSync).not.toHaveBeenCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/config.json/), - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com,some-domain.es", - "port": "3000", - "location": "/" - } - ], null, 2) - ); - }); - - test("domain config created sucessfully (does not exists /ssl)", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - vi.spyOn(fs, "existsSync").mockReturnValue(false); - - crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); - - const domain = "some-domain.com"; - const port = "3000"; - - onCreateAction(domain, { port }); - - expect(fs.readFileSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.local-ssl-management\/config.json/), - { encoding: "utf8" } - ); - expect(fs.existsSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/ssl/), - ); - expect(fs.mkdirSync).toHaveBeenCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledWith( - expect.stringMatching(/.local-ssl-management\/config.json/), - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": "3000", - "location": "/" - } - ], null, 2) - ); - }); - - test("domain config already exists", () => { - vi.spyOn(shell, "echo").mockImplementation(vi.fn(() => ShellString("1"))); - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": "3000", - "location": "/" - } - ], null, 2)); - - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); - - const domain = "some-domain.com"; - const port = "3000"; - - expect(() => { onCreateAction(domain, { port }); }).toThrow(); - - expect(shell.echo).toHaveBeenCalledWith("\n[Error] - Domain already exists\n"); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - }); - }) + describe("failures", () => { + beforeEach(() => { + vi.spyOn(shell, "echo").mockImplementation((v) => ShellString(v)); + vi.spyOn(shell, "exit").mockImplementation(() => + Promise.resolve(1 as never), + ); + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + }); + + test("can not create with invalid domain", () => { + const domain = "wrong.domain"; + const port = 3000; + + expect(() => { + onCreateAction(domain, { port }); + }).toThrow(); + + expect(shell.echo).toHaveBeenCalledWith( + "\n[Error] - Domain (https://wrong.domain)format is not valid\n", + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + + test("can not create with invalid port", () => { + const domain = "some-domain.com"; + const port = 666; + + expect(() => { + onCreateAction(domain, { port }); + }).toThrow(); + + expect(shell.echo).toHaveBeenCalledWith( + "\n[Error] - Port (--port ) should be into the range 1025 to 65535\n", + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + }); + + describe("success", () => { + beforeEach(() => { + vi.clearAllMocks(); + + vi.spyOn(fs, "mkdirSync"); + (vi.spyOn(fs, "readdirSync") as SpyInstance).mockImplementation(() => [ + "some-domain.com-cert.pem", + "some-domain.com-key.pem", + ]); + vi.spyOn(fs, "existsSync").mockReturnValue(true); + vi.spyOn(shell, "exec").mockImplementation(() => { + return { stdout: "200" }; + }); + }); + + describe("double service", () => { + test("domain config created sucessfully (double location)", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "a5051812-e151-4ca3-b9b6-b86f6fb05817", + domain: "some-domain.com", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + + crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); + + const domain = "some-domain.com"; + const port = 3000; + const location = "/lala"; + + onCreateAction(domain, { port, location }); + + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.local-ssl-management\/config.json/), + { encoding: "utf8" }, + ); + expect(fs.existsSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/ssl/), + ); + expect(fs.mkdirSync).not.toHaveBeenCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledTimes(3); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 3, + expect.stringMatching(/.local-ssl-management\/config.json/i), + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: "3000,3000", + location: "/,/lala", + }, + ], + null, + 2, + ), + ); + }); + + test("domain config created sucessfully (double location with different port)", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "a5051812-e151-4ca3-b9b6-b86f6fb05817", + domain: "some-domain.com", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + + crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); + + const domain = "some-domain.com"; + const port = 4000; + const location = "/lala"; + + onCreateAction(domain, { port, location }); + + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.local-ssl-management\/config.json/), + { encoding: "utf8" }, + ); + expect(fs.existsSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/ssl/), + ); + expect(fs.mkdirSync).not.toHaveBeenCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledTimes(3); + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 3, + expect.stringMatching(/.local-ssl-management\/config.json/i), + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: "3000,4000", + location: "/,/lala", + }, + ], + null, + 2, + ), + ); + }); + }); + + describe("single service", () => { + test("domain config created sucessfully", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + + crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); + + const domain = "some-domain.com"; + const port = "3000"; + + onCreateAction(domain, { port }); + + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.local-ssl-management\/config.json/), + { encoding: "utf8" }, + ); + expect(fs.existsSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/ssl/), + ); + expect(fs.mkdirSync).not.toHaveBeenCalled(); + + expect(fs.writeFileSync).toHaveBeenNthCalledWith( + 3, + expect.stringMatching(/.local-ssl-management\/config.json/), + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + }); + + test("double domain config created sucessfully", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + + crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); + + const domain = "some-domain.com,some-domain.es"; + const port = "3000"; + + onCreateAction(domain, { port }); + + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.local-ssl-management\/config.json/), + { encoding: "utf8" }, + ); + expect(fs.existsSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/ssl/), + ); + expect(fs.mkdirSync).not.toHaveBeenCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/config.json/), + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com,some-domain.es", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + }); + + test("domain config created sucessfully (does not exists /ssl)", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + vi.spyOn(fs, "existsSync").mockReturnValue(false); + + crypto.randomUUID = vi.fn(() => "48d1a85c-377a-40ef-8a82-d1405f7a074f"); + + const domain = "some-domain.com"; + const port = "3000"; + + onCreateAction(domain, { port }); + + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.local-ssl-management\/config.json/), + { encoding: "utf8" }, + ); + expect(fs.existsSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/ssl/), + ); + expect(fs.mkdirSync).toHaveBeenCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledWith( + expect.stringMatching(/.local-ssl-management\/config.json/), + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + }); + + test("domain config already exists", () => { + vi.spyOn(shell, "echo").mockImplementation( + vi.fn(() => ShellString("1")), + ); + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: "3000", + location: "/", + }, + ], + null, + 2, + ), + ); + + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); + + const domain = "some-domain.com"; + const port = "3000"; + + expect(() => { + onCreateAction(domain, { port }); + }).toThrow(); + + expect(shell.echo).toHaveBeenCalledWith( + "\n[Error] - Domain already exists\n", + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + }); + }); }); diff --git a/packages/cli/src/on-create-action.ts b/packages/cli/src/on-create-action.ts index 2e32247..b71f026 100644 --- a/packages/cli/src/on-create-action.ts +++ b/packages/cli/src/on-create-action.ts @@ -1,12 +1,12 @@ -import fs from "fs"; +// import path from "path"; +import type { Config } from "@dimaslz/local-ssl-management-core"; +import chalk from "chalk"; import crypto from "crypto"; +import fs from "fs"; import shell from "shelljs"; -import chalk from "chalk"; -// import path from "path"; -import type { Config } from "@dimaslz/local-ssl-management-core"; -import { validateDomain, validatePort, validateLocation } from "./utils"; import generateProxyImage from "./generate-proxy-image"; +import { validateDomain, validateLocation, validatePort } from "./utils"; // const distPath = path.resolve(__dirname, "./"); // const rootPath = `${distPath}/.local-ssl-management`; @@ -14,72 +14,83 @@ const rootPath = `.local-ssl-management`; const sslPath = `${rootPath}/ssl`; const configPath = `${rootPath}/config.json`; - -const onCreateAction = (_domain: string, options: { port: string, location?: string; }) => { - const config: Config[] = JSON.parse(fs.readFileSync(configPath, { encoding: "utf8" }) || "[]"); - - let { location = "/" } = options as { port: string; location: string; }; - const { port } = options as { port: string; location: string; }; - - validateLocation(location); - validatePort(port); - validateDomain(_domain); - - const domains = config - .map((c) => c.domain.split(",") - .map(d => d.trim()).join("_") - ).concat("localhost"); - - if (!fs.existsSync(sslPath)) { - fs.mkdirSync(sslPath, { recursive: true }); - } - - const filesToRemove = fs.readdirSync(sslPath) - .filter((file) => { - const f = file.replace(/-?cert\..+?$|-?key\..+?$/, ""); - return !domains.includes(f) - }); - - filesToRemove.forEach(file => fs.unlinkSync(`${sslPath}/${file}`)) - - const domain = _domain.split(",").map(d => d.trim()).join(","); - const domainExists = config.some((c) => c.domain === domain); - const domainIndex = config.findIndex((c) => c.domain === domain); - let currentLocation: string = config.find((c) => c.domain === domain)?.location || "/"; - let currentPort: string = config.find((c) => c.domain === domain)?.port; - - if (domainExists) { - shell.echo(chalk.red("\n[Error] - Domain already exists\n")); - shell.exit(1); - } - - if (currentLocation) { - currentLocation += `,${location}`; - } - - if (currentPort) { - currentPort += `,${port}`; - } - - if (domainIndex > -1) { - config[domainIndex] = { - id: crypto.randomUUID(), - domain, - port: currentPort, - location: currentLocation, - } as Config; - } else { - config.push({ - id: crypto.randomUUID(), - domain, - port, - location: "/", - } as Config); - } - - generateProxyImage(config); - - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); +const onCreateAction = ( + _domain: string, + options: { port: string; location?: string }, +) => { + const config: Config[] = JSON.parse( + fs.readFileSync(configPath, { encoding: "utf8" }) || "[]", + ); + + const { location = "/" } = options as { port: string; location: string }; + const { port } = options as { port: string; location: string }; + + validateLocation(location); + validatePort(port); + validateDomain(_domain); + + const domains = config + .map((c) => + c.domain + .split(",") + .map((d) => d.trim()) + .join("_"), + ) + .concat("localhost"); + + if (!fs.existsSync(sslPath)) { + fs.mkdirSync(sslPath, { recursive: true }); + } + + const filesToRemove = fs.readdirSync(sslPath).filter((file) => { + const f = file.replace(/-?cert\..+?$|-?key\..+?$/, ""); + return !domains.includes(f); + }); + + filesToRemove.forEach((file) => fs.unlinkSync(`${sslPath}/${file}`)); + + const domain = _domain + .split(",") + .map((d) => d.trim()) + .join(","); + const domainExists = config.some((c) => c.domain === domain); + const domainIndex = config.findIndex((c) => c.domain === domain); + let currentLocation: string = + config.find((c) => c.domain === domain)?.location || "/"; + let currentPort: string = config.find((c) => c.domain === domain)?.port; + + if (domainExists) { + shell.echo(chalk.red("\n[Error] - Domain already exists\n")); + shell.exit(1); + } + + if (currentLocation) { + currentLocation += `,${location}`; + } + + if (currentPort) { + currentPort += `,${port}`; + } + + if (domainIndex > -1) { + config[domainIndex] = { + id: crypto.randomUUID(), + domain, + port: currentPort, + location: currentLocation, + } as Config; + } else { + config.push({ + id: crypto.randomUUID(), + domain, + port, + location: "/", + } as Config); + } + + generateProxyImage(config); + + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); }; export default onCreateAction; diff --git a/packages/cli/src/on-list-action.test.ts b/packages/cli/src/on-list-action.test.ts index bd73bae..73cad46 100644 --- a/packages/cli/src/on-list-action.test.ts +++ b/packages/cli/src/on-list-action.test.ts @@ -6,42 +6,48 @@ import onListAction from "./on-list-action"; vi.mock("fs"); vi.mock("shelljs", async () => ({ - default: { - exec: vi.fn((v) => v), - echo: vi.fn((v) => v), - exit: vi.fn((v) => v) - } + default: { + exec: vi.fn((v) => v), + echo: vi.fn((v) => v), + exit: vi.fn((v) => v), + }, })); describe("On list action", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - test("no domains available", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); - - expect(() => { onListAction(); }).toThrow(); - - expect(shell.echo).toHaveBeenCalledWith(`\nDoes not exists configs yet.\n`); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - - test("list domains availables", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "domain": "local.some-domain.tld", - "port": "3333" - }, - ])); - - onListAction(); - - expect(shell.echo).toHaveBeenCalledWith(` + beforeEach(() => { + vi.clearAllMocks(); + }); + + test("no domains available", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); + + expect(() => { + onListAction(); + }).toThrow(); + + expect(shell.echo).toHaveBeenCalledWith(`\nDoes not exists configs yet.\n`); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + + test("list domains availables", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify([ + { + id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + domain: "local.some-domain.tld", + port: "3333", + }, + ]), + ); + + onListAction(); + + expect(shell.echo).toHaveBeenCalledWith(` id key domains port xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx local.some-domain.tld https://local.some-domain.tld 3333 `); - }); + }); }); diff --git a/packages/cli/src/on-list-action.ts b/packages/cli/src/on-list-action.ts index d44bd2a..74518bf 100644 --- a/packages/cli/src/on-list-action.ts +++ b/packages/cli/src/on-list-action.ts @@ -1,44 +1,61 @@ -import path from "path"; +import type { Config } from "@dimaslz/local-ssl-management-core"; +import Table from "cli-table"; import fs from "fs"; +import path from "path"; import shell from "shelljs"; -import Table from "cli-table"; - -import type { Config } from "@dimaslz/local-ssl-management-core"; const distPath = path.resolve(__dirname, "./"); const rootPath = `${distPath}/.local-ssl-management`; const configPath = `${rootPath}/config.json`; - const onListAction = () => { - const config: Config[] = JSON.parse(fs.readFileSync(configPath, { encoding: "utf8" }) || "[]"); - - if (!config.length) { - shell.echo(`\nDoes not exists configs yet.\n`); - shell.exit(1); - } - - const table = new Table({ - head: ["id", "key", "domains", "port"], - chars: { - 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '' - , 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '' - , 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '' - , 'right': '', 'right-mid': '', 'middle': ' ' - }, - style: { 'padding-left': 0, 'padding-right': 0 }, - }); - - config.forEach(({ id, domain, port }) => { - table.push([ - id, - domain.split(",").map(i => i.trim()).join("_"), - domain.split(",").map((d) => `https://${d.trim()}`).join(", "), - String(port) - ]); - }); - - shell.echo(`\n${table.toString()}\n`); + const config: Config[] = JSON.parse( + fs.readFileSync(configPath, { encoding: "utf8" }) || "[]", + ); + + if (!config.length) { + shell.echo(`\nDoes not exists configs yet.\n`); + shell.exit(1); + } + + const table = new Table({ + head: ["id", "key", "domains", "port"], + chars: { + top: "", + "top-mid": "", + "top-left": "", + "top-right": "", + bottom: "", + "bottom-mid": "", + "bottom-left": "", + "bottom-right": "", + left: "", + "left-mid": "", + mid: "", + "mid-mid": "", + right: "", + "right-mid": "", + middle: " ", + }, + style: { "padding-left": 0, "padding-right": 0 }, + }); + + config.forEach(({ id, domain, port }) => { + table.push([ + id, + domain + .split(",") + .map((i) => i.trim()) + .join("_"), + domain + .split(",") + .map((d) => `https://${d.trim()}`) + .join(", "), + String(port), + ]); + }); + + shell.echo(`\n${table.toString()}\n`); }; export default onListAction; diff --git a/packages/cli/src/on-remove-action.test.ts b/packages/cli/src/on-remove-action.test.ts index 3b03042..587cfc1 100644 --- a/packages/cli/src/on-remove-action.test.ts +++ b/packages/cli/src/on-remove-action.test.ts @@ -1,178 +1,218 @@ +import crypto from "crypto"; import fs from "fs"; import shell from "shelljs"; -import crypto from "crypto"; -import onRemoveAction from "./on-remove-action"; import generateProxyImage from "./generate-proxy-image"; +import onRemoveAction from "./on-remove-action"; vi.mock("path", () => ({ - default: { - resolve: () => "/root/path" - } + default: { + resolve: () => "/root/path", + }, })); vi.mock("fs"); vi.mock("shelljs", async () => ({ - default: { - exec: vi.fn((v) => v), - echo: vi.fn((v) => v), - exit: vi.fn((v) => v) - } + default: { + exec: vi.fn((v) => v), + echo: vi.fn((v) => v), + exit: vi.fn((v) => v), + }, })); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); vi.mock("./generate-proxy-image"); describe("On remove action", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe("failure", () => { - test("removing domain by domain name does not exists", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - - onRemoveAction("dummy"); - - expect(shell.echo).toHaveBeenCalledWith(`\n[Error] - Domain "dummy" does not exists\n`); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - - test("remove domain by id does not exists", () => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); - - onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); - - expect(shell.echo).toHaveBeenCalledWith(`\n[Error] - Domain with id \"6eb61d17-ba78-4618-a2ac-47aeb4ba8b26\" does not exists\n`); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - }); - - describe("success", () => { - test("remove domain by id", () => { - vi.spyOn(fs, "existsSync").mockReturnValue(true); - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", - "domain": "local.some-domain.tld", - "port": "3333" - }, - ])); - - onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); - - expect(fs.existsSync).toHaveBeenCalledTimes(2); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 1, expect.stringMatching(/.*?\/local.some-domain.tld-cert.pem$/g) - ); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 2, expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g) - ); - - expect(fs.unlinkSync).toHaveBeenCalledTimes(2); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 1, expect.stringMatching(/.*?\/local.some-domain.tld-cert.pem$/g) - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 2, expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g) - ); - expect(shell.echo).toHaveBeenCalledTimes(2); - expect(shell.echo).toHaveBeenNthCalledWith(1, `\n[Success] - šŸŽ‰ Domain removed succesful.\n`); - expect(shell.echo).toHaveBeenNthCalledWith(2, `\n[Action] - šŸ”„ Updating proxy image.\n`); - expect(generateProxyImage).toBeCalled(); - }); - - test("remove domain by domain name", () => { - vi.spyOn(fs, "existsSync").mockReturnValue(true); - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", - "domain": "local.some-domain.tld", - "port": "3333" - }, - ])); - - onRemoveAction("local.some-domain.tld"); - - expect(fs.existsSync).toHaveBeenCalledTimes(2); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 1, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem" - ); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 2, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-key.pem" - ); - - expect(fs.unlinkSync).toHaveBeenCalledTimes(2); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 1, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem" - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 2, expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g) - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 1, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem" - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 2, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-key.pem" - ); - expect(fs.writeFileSync).toHaveBeenCalledWith( - "/root/path/.local-ssl-management/config.json", - JSON.stringify([], null, 2) - ); - - expect(shell.echo).toHaveBeenCalledTimes(2); - expect(shell.echo).toHaveBeenNthCalledWith(1, `\n[Success] - šŸŽ‰ Domain removed succesful.\n`); - expect(shell.echo).toHaveBeenNthCalledWith(2, `\n[Action] - šŸ”„ Updating proxy image.\n`); - - expect(generateProxyImage).toBeCalled(); - }); - - test("remove multiple domain by domain key", () => { - vi.spyOn(fs, "existsSync").mockReturnValue(true); - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", - "domain": "demo.com,demo.es", - "port": "3333" - }, - ])); - - crypto.randomUUID = vi.fn(() => "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26") - - onRemoveAction("demo.com_demo.es"); - - expect(fs.existsSync).toHaveBeenCalledTimes(2); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 1, - expect.stringMatching(/.*?\/demo.com_demo.es-cert.pem$/g) - ); - expect(fs.existsSync).toHaveBeenNthCalledWith( - 2, - expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g) - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 1, expect.stringMatching(/.*?\/demo.com_demo.es-cert.pem$/g) - ); - expect(fs.unlinkSync).toHaveBeenNthCalledWith( - 2, expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g) - ); - expect(fs.writeFileSync).toHaveBeenCalledWith( - expect.stringMatching(/.*?\/\.local-ssl-management\/config.json$/g), - JSON.stringify([], null, 2) - ); - - expect(shell.echo).toHaveBeenCalledTimes(2); - expect(shell.echo).toHaveBeenNthCalledWith(1, `\n[Success] - šŸŽ‰ Domain removed succesful.\n`); - expect(shell.echo).toHaveBeenNthCalledWith(2, `\n[Action] - šŸ”„ Updating proxy image.\n`); - - expect(generateProxyImage).toBeCalled(); - }); - }); + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("failure", () => { + test("removing domain by domain name does not exists", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + + onRemoveAction("dummy"); + + expect(shell.echo).toHaveBeenCalledWith( + `\n[Error] - Domain "dummy" does not exists\n`, + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + + test("remove domain by id does not exists", () => { + vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); + + onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); + + expect(shell.echo).toHaveBeenCalledWith( + `\n[Error] - Domain with id "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26" does not exists\n`, + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + }); + + describe("success", () => { + test("remove domain by id", () => { + vi.spyOn(fs, "existsSync").mockReturnValue(true); + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify([ + { + id: "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", + domain: "local.some-domain.tld", + port: "3333", + }, + ]), + ); + + onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); + + expect(fs.existsSync).toHaveBeenCalledTimes(2); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.*?\/local.some-domain.tld-cert.pem$/g), + ); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 2, + expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g), + ); + + expect(fs.unlinkSync).toHaveBeenCalledTimes(2); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.*?\/local.some-domain.tld-cert.pem$/g), + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 2, + expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g), + ); + expect(shell.echo).toHaveBeenCalledTimes(2); + expect(shell.echo).toHaveBeenNthCalledWith( + 1, + `\n[Success] - šŸŽ‰ Domain removed succesful.\n`, + ); + expect(shell.echo).toHaveBeenNthCalledWith( + 2, + `\n[Action] - šŸ”„ Updating proxy image.\n`, + ); + expect(generateProxyImage).toBeCalled(); + }); + + test("remove domain by domain name", () => { + vi.spyOn(fs, "existsSync").mockReturnValue(true); + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify([ + { + id: "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", + domain: "local.some-domain.tld", + port: "3333", + }, + ]), + ); + + onRemoveAction("local.some-domain.tld"); + + expect(fs.existsSync).toHaveBeenCalledTimes(2); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem", + ); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/ssl/local.some-domain.tld-key.pem", + ); + + expect(fs.unlinkSync).toHaveBeenCalledTimes(2); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem", + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 2, + expect.stringMatching(/.*?\/local.some-domain.tld-key.pem$/g), + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/ssl/local.some-domain.tld-cert.pem", + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 2, + "/root/path/.local-ssl-management/ssl/local.some-domain.tld-key.pem", + ); + expect(fs.writeFileSync).toHaveBeenCalledWith( + "/root/path/.local-ssl-management/config.json", + JSON.stringify([], null, 2), + ); + + expect(shell.echo).toHaveBeenCalledTimes(2); + expect(shell.echo).toHaveBeenNthCalledWith( + 1, + `\n[Success] - šŸŽ‰ Domain removed succesful.\n`, + ); + expect(shell.echo).toHaveBeenNthCalledWith( + 2, + `\n[Action] - šŸ”„ Updating proxy image.\n`, + ); + + expect(generateProxyImage).toBeCalled(); + }); + + test("remove multiple domain by domain key", () => { + vi.spyOn(fs, "existsSync").mockReturnValue(true); + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify([ + { + id: "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26", + domain: "demo.com,demo.es", + port: "3333", + }, + ]), + ); + + crypto.randomUUID = vi.fn(() => "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); + + onRemoveAction("demo.com_demo.es"); + + expect(fs.existsSync).toHaveBeenCalledTimes(2); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.*?\/demo.com_demo.es-cert.pem$/g), + ); + expect(fs.existsSync).toHaveBeenNthCalledWith( + 2, + expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g), + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 1, + expect.stringMatching(/.*?\/demo.com_demo.es-cert.pem$/g), + ); + expect(fs.unlinkSync).toHaveBeenNthCalledWith( + 2, + expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g), + ); + expect(fs.writeFileSync).toHaveBeenCalledWith( + expect.stringMatching(/.*?\/\.local-ssl-management\/config.json$/g), + JSON.stringify([], null, 2), + ); + + expect(shell.echo).toHaveBeenCalledTimes(2); + expect(shell.echo).toHaveBeenNthCalledWith( + 1, + `\n[Success] - šŸŽ‰ Domain removed succesful.\n`, + ); + expect(shell.echo).toHaveBeenNthCalledWith( + 2, + `\n[Action] - šŸ”„ Updating proxy image.\n`, + ); + + expect(generateProxyImage).toBeCalled(); + }); + }); }); diff --git a/packages/cli/src/on-remove-action.ts b/packages/cli/src/on-remove-action.ts index 23d7d01..b83783d 100644 --- a/packages/cli/src/on-remove-action.ts +++ b/packages/cli/src/on-remove-action.ts @@ -1,9 +1,9 @@ +import type { Config } from "@dimaslz/local-ssl-management-core"; +import chalk from "chalk"; import fs from "fs"; import path from "path"; import shell from "shelljs"; -import type { Config } from "@dimaslz/local-ssl-management-core"; -import chalk from "chalk"; import generateProxyImage from "./generate-proxy-image"; const distPath = path.resolve(__dirname, "./"); @@ -11,61 +11,66 @@ const rootPath = `${distPath}/.local-ssl-management`; const configPath = `${rootPath}/config.json`; const sslPath = `${rootPath}/ssl`; - const onRemoveAction = (_domain: string) => { - const config: Config[] = JSON.parse(fs.readFileSync(configPath, { encoding: "utf8" }) || "[]"); + const config: Config[] = JSON.parse( + fs.readFileSync(configPath, { encoding: "utf8" }) || "[]", + ); - const v4 = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i); - const isUUID = v4.test(_domain); + const v4 = new RegExp( + /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + ); + const isUUID = v4.test(_domain); - const domain = _domain.split("_").join(","); + const domain = _domain.split("_").join(","); - const exists = isUUID - ? config.some((c) => c.id === _domain) - : config.some((c) => c.domain === domain); + const exists = isUUID + ? config.some((c) => c.id === _domain) + : config.some((c) => c.domain === domain); - if (!exists) { - if (isUUID) { - shell.echo(chalk.red(`\n[Error] - Domain with id "${_domain}" does not exists\n`)); - } else { - shell.echo(chalk.red(`\n[Error] - Domain "${domain}" does not exists\n`)); - } + if (!exists) { + if (isUUID) { + shell.echo( + chalk.red(`\n[Error] - Domain with id "${_domain}" does not exists\n`), + ); + } else { + shell.echo(chalk.red(`\n[Error] - Domain "${domain}" does not exists\n`)); + } - shell.exit(1); - } + shell.exit(1); + } - let newConfig = isUUID - ? config.filter((c) => c.id !== _domain) - : config.filter((c) => c.domain !== domain); + const newConfig = isUUID + ? config.filter((c) => c.id !== _domain) + : config.filter((c) => c.domain !== domain); - const domainData = config.find(c => { - if (isUUID) { - return c.id === _domain; - } + const domainData = config.find((c) => { + if (isUUID) { + return c.id === _domain; + } - return c.domain === domain; - }); + return c.domain === domain; + }); - const certFile = `${domainData?.domain.split(",").join("_")}-cert.pem`; - const keyFile = `${domainData?.domain.split(",").join("_")}-key.pem`; + const certFile = `${domainData?.domain.split(",").join("_")}-cert.pem`; + const keyFile = `${domainData?.domain.split(",").join("_")}-key.pem`; - const certFileExists = fs.existsSync(`${sslPath}/${certFile}`); - const keyFileExists = fs.existsSync(`${sslPath}/${keyFile}`); + const certFileExists = fs.existsSync(`${sslPath}/${certFile}`); + const keyFileExists = fs.existsSync(`${sslPath}/${keyFile}`); - if (certFileExists) { - fs.unlinkSync(`${sslPath}/${certFile}`); - } + if (certFileExists) { + fs.unlinkSync(`${sslPath}/${certFile}`); + } - if (keyFileExists) { - fs.unlinkSync(`${sslPath}/${keyFile}`); - } + if (keyFileExists) { + fs.unlinkSync(`${sslPath}/${keyFile}`); + } - fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2)); + fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2)); - shell.echo(chalk.green("\n[Success] - šŸŽ‰ Domain removed succesful.\n")); - shell.echo(chalk.green("\n[Action] - šŸ”„ Updating proxy image.\n")); + shell.echo(chalk.green("\n[Success] - šŸŽ‰ Domain removed succesful.\n")); + shell.echo(chalk.green("\n[Action] - šŸ”„ Updating proxy image.\n")); - generateProxyImage(newConfig); + generateProxyImage(newConfig); }; export default onRemoveAction; diff --git a/packages/cli/src/on-update-action.test.ts b/packages/cli/src/on-update-action.test.ts index 8aa9bf5..8bee669 100644 --- a/packages/cli/src/on-update-action.test.ts +++ b/packages/cli/src/on-update-action.test.ts @@ -1,156 +1,200 @@ import fs from "fs"; import shell from "shelljs"; +import generateProxyImage from "./generate-proxy-image"; import onUpdateAction from "./on-update-action"; import validatePort from "./utils/validate-port"; -import generateProxyImage from "./generate-proxy-image"; vi.mock("./generate-proxy-image"); vi.mock("./utils/validate-port"); vi.mock("fs"); vi.mock("shelljs"); vi.mock("@dimaslz/local-ssl-management-core", () => ({ - mkcert: vi.fn(), - getLocalIP: vi.fn(() => "192.168.0.0"), + mkcert: vi.fn(), + getLocalIP: vi.fn(() => "192.168.0.0"), })); vi.mock("./list-container"); vi.mock("path", () => ({ - default: { - resolve: () => "/root/path" - } + default: { + resolve: () => "/root/path", + }, })); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); describe("On update action", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe("failures", () => { - test("update domain by wrong domain key", () => { - const domain = "foo-domain.com"; - const port = 3333; - - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3000 - } - ], null, 2)); - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); - - expect(() => { onUpdateAction(domain, { port }); }).toThrow(); - - expect(shell.echo).toBeCalledWith("\n[Error] - Domain \"foo-domain.com\" does not exists\n") - expect(shell.exit).toBeCalledWith(1); - }); - - test("update domain by wrong id", () => { - const domain = "48d1a85c-377a-40ef-8a82-d1405f7a0722"; - const port = 3333; - - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3000 - } - ], null, 2)); - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); - - expect(() => { onUpdateAction(domain, { port }); }).toThrow(); - - expect(shell.echo).toBeCalledWith("\n[Error] - Domain with key \"48d1a85c-377a-40ef-8a82-d1405f7a0722\" does not exists\n") - expect(shell.exit).toBeCalledWith(1); - }); - }); - - describe("success", () => { - test("update domain by domain key", () => { - const domain = "some-domain.com"; - const port = 3333; - - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3000 - } - ], null, 2)); - - onUpdateAction(domain, { port }); - - expect(validatePort).toBeCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledWith( - "/root/path/.local-ssl-management/config.json", - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3333 - } - ], null, 2) - ); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\n[Success] - šŸŽ‰ Domain removed succesful.\n" - ); - expect(shell.echo).nthCalledWith( - 2, - "\n[Action] - šŸ”„ Updating proxy image.\n" - ); - - expect(generateProxyImage).toBeCalled(); - }); - - test("update domain by domain id", () => { - const domain = "48d1a85c-377a-40ef-8a82-d1405f7a074f"; - const port = 3333; - - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3000 - } - ], null, 2)); - - onUpdateAction(domain, { port }); - - expect(validatePort).toBeCalled(); - - expect(fs.writeFileSync).toHaveBeenCalledWith( - "/root/path/.local-ssl-management/config.json", - JSON.stringify([ - { - "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", - "domain": "some-domain.com", - "port": 3333 - } - ], null, 2) - ); - - expect(shell.echo).toBeCalledTimes(2); - expect(shell.echo).nthCalledWith( - 1, - "\n[Success] - šŸŽ‰ Domain removed succesful.\n" - ); - expect(shell.echo).nthCalledWith( - 2, - "\n[Action] - šŸ”„ Updating proxy image.\n" - ); - - expect(generateProxyImage).toBeCalled(); - }); - }); -}); \ No newline at end of file + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("failures", () => { + test("update domain by wrong domain key", () => { + const domain = "foo-domain.com"; + const port = 3333; + + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3000, + }, + ], + null, + 2, + ), + ); + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); + + expect(() => { + onUpdateAction(domain, { port }); + }).toThrow(); + + expect(shell.echo).toBeCalledWith( + '\n[Error] - Domain "foo-domain.com" does not exists\n', + ); + expect(shell.exit).toBeCalledWith(1); + }); + + test("update domain by wrong id", () => { + const domain = "48d1a85c-377a-40ef-8a82-d1405f7a0722"; + const port = 3333; + + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3000, + }, + ], + null, + 2, + ), + ); + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); + + expect(() => { + onUpdateAction(domain, { port }); + }).toThrow(); + + expect(shell.echo).toBeCalledWith( + '\n[Error] - Domain with key "48d1a85c-377a-40ef-8a82-d1405f7a0722" does not exists\n', + ); + expect(shell.exit).toBeCalledWith(1); + }); + }); + + describe("success", () => { + test("update domain by domain key", () => { + const domain = "some-domain.com"; + const port = 3333; + + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3000, + }, + ], + null, + 2, + ), + ); + + onUpdateAction(domain, { port }); + + expect(validatePort).toBeCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledWith( + "/root/path/.local-ssl-management/config.json", + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3333, + }, + ], + null, + 2, + ), + ); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith( + 1, + "\n[Success] - šŸŽ‰ Domain removed succesful.\n", + ); + expect(shell.echo).nthCalledWith( + 2, + "\n[Action] - šŸ”„ Updating proxy image.\n", + ); + + expect(generateProxyImage).toBeCalled(); + }); + + test("update domain by domain id", () => { + const domain = "48d1a85c-377a-40ef-8a82-d1405f7a074f"; + const port = 3333; + + vi.spyOn(fs, "readFileSync").mockReturnValue( + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3000, + }, + ], + null, + 2, + ), + ); + + onUpdateAction(domain, { port }); + + expect(validatePort).toBeCalled(); + + expect(fs.writeFileSync).toHaveBeenCalledWith( + "/root/path/.local-ssl-management/config.json", + JSON.stringify( + [ + { + id: "48d1a85c-377a-40ef-8a82-d1405f7a074f", + domain: "some-domain.com", + port: 3333, + }, + ], + null, + 2, + ), + ); + + expect(shell.echo).toBeCalledTimes(2); + expect(shell.echo).nthCalledWith( + 1, + "\n[Success] - šŸŽ‰ Domain removed succesful.\n", + ); + expect(shell.echo).nthCalledWith( + 2, + "\n[Action] - šŸ”„ Updating proxy image.\n", + ); + + expect(generateProxyImage).toBeCalled(); + }); + }); +}); diff --git a/packages/cli/src/on-update-action.ts b/packages/cli/src/on-update-action.ts index 0bfd145..b336941 100644 --- a/packages/cli/src/on-update-action.ts +++ b/packages/cli/src/on-update-action.ts @@ -1,9 +1,9 @@ +import { Config } from "@dimaslz/local-ssl-management-core"; +import chalk from "chalk"; import fs from "fs"; import path from "path"; import shell from "shelljs"; -import { Config } from "@dimaslz/local-ssl-management-core"; -import chalk from "chalk"; import generateProxyImage from "./generate-proxy-image"; import { validatePort } from "./utils"; @@ -11,45 +11,50 @@ const distPath = path.resolve(__dirname, "./"); const rootPath = `${distPath}/.local-ssl-management`; const configPath = `${rootPath}/config.json`; - const onUpdateAction = (domain: string, options: { port: number }) => { - const config: Config[] = JSON.parse(fs.readFileSync(configPath, { encoding: "utf8" }) || "[]"); + const config: Config[] = JSON.parse( + fs.readFileSync(configPath, { encoding: "utf8" }) || "[]", + ); - const v4 = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i); - const isUUID = v4.test(domain); + const v4 = new RegExp( + /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + ); + const isUUID = v4.test(domain); - const exists = isUUID - ? config.some((c) => c.id === domain) - : config.some((c) => c.domain === domain); + const exists = isUUID + ? config.some((c) => c.id === domain) + : config.some((c) => c.domain === domain); - if (!exists) { - if (isUUID) { - shell.echo(chalk.red(`\n[Error] - Domain with key "${domain}" does not exists\n`)); - } else { - shell.echo(chalk.red(`\n[Error] - Domain "${domain}" does not exists\n`)); - } + if (!exists) { + if (isUUID) { + shell.echo( + chalk.red(`\n[Error] - Domain with key "${domain}" does not exists\n`), + ); + } else { + shell.echo(chalk.red(`\n[Error] - Domain "${domain}" does not exists\n`)); + } - shell.exit(1); - } + shell.exit(1); + } - const { port } = options; + const { port } = options; - validatePort(port); + validatePort(port); - const newConfig = config.map((c) => { - if ((isUUID && c.id === domain) || c.domain === domain) { - c.port = port; - } + const newConfig = config.map((c) => { + if ((isUUID && c.id === domain) || c.domain === domain) { + c.port = port; + } - return c; - }); + return c; + }); - fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2)); + fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2)); - shell.echo(chalk.green("\n[Success] - šŸŽ‰ Domain removed succesful.\n")); - shell.echo(chalk.green("\n[Action] - šŸ”„ Updating proxy image.\n")); + shell.echo(chalk.green("\n[Success] - šŸŽ‰ Domain removed succesful.\n")); + shell.echo(chalk.green("\n[Action] - šŸ”„ Updating proxy image.\n")); - generateProxyImage(newConfig); + generateProxyImage(newConfig); }; export default onUpdateAction; diff --git a/packages/cli/src/templates.ts b/packages/cli/src/templates.ts index b10c092..1a6cd93 100644 --- a/packages/cli/src/templates.ts +++ b/packages/cli/src/templates.ts @@ -1,5 +1,5 @@ export default { - nginxLocation: `location %LOCATION% { + nginxLocation: `location %LOCATION% { gzip on; gzip_disable "msie6"; gzip_vary on; @@ -22,7 +22,7 @@ export default { proxy_set_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; expires off; }`, - dockerfile: `FROM nginx + dockerfile: `FROM nginx # RUN rm -f /etc/nginx/conf.d/default.conf @@ -42,7 +42,7 @@ COPY #-main-path-#nginx.conf /etc/nginx/ EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"]`, - nginxConfServer: `server { + nginxConfServer: `server { listen 443 ssl; autoindex off; @@ -60,7 +60,7 @@ CMD ["nginx", "-g", "daemon off;"]`, #--server-location--# }`, - nginxConf: `user nginx; + nginxConf: `user nginx; worker_processes 20; error_log /var/log/nginx/error.log warn; @@ -94,5 +94,5 @@ http { } #--server-config--# -}` -} \ No newline at end of file +}`, +}; diff --git a/packages/cli/src/utils/index.ts b/packages/cli/src/utils/index.ts index e9e8ee0..96358a6 100644 --- a/packages/cli/src/utils/index.ts +++ b/packages/cli/src/utils/index.ts @@ -1,3 +1,3 @@ -export { default as validatePort } from "./validate-port"; export { default as validateDomain } from "./validate-domain"; export { default as validateLocation } from "./validate-location"; +export { default as validatePort } from "./validate-port"; diff --git a/packages/cli/src/utils/validate-domain.test.ts b/packages/cli/src/utils/validate-domain.test.ts index 5e9323a..9c7b79b 100644 --- a/packages/cli/src/utils/validate-domain.test.ts +++ b/packages/cli/src/utils/validate-domain.test.ts @@ -2,59 +2,71 @@ import shell from "shelljs"; import validateDomain from "./validate-domain"; -vi.mock('shelljs'); +vi.mock("shelljs"); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); describe("Validate domain", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); + beforeEach(() => { + vi.clearAllMocks(); + }); - describe("wrong TLD", () => { - test("domain with wrong TLD should not be acceptable", () => { - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); + describe("wrong TLD", () => { + test("domain with wrong TLD should not be acceptable", () => { + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); - const domain = "your-domain.FAKE_TLD"; + const domain = "your-domain.FAKE_TLD"; - expect(() => { validateDomain(domain); }).toThrow(); + expect(() => { + validateDomain(domain); + }).toThrow(); - expect(shell.echo).toBeCalledWith(`\n[Error] - Domain (https://your-domain.FAKE_TLD)format is not valid\n`); - expect(shell.exit).toHaveBeenCalledWith(1); - }); + expect(shell.echo).toBeCalledWith( + `\n[Error] - Domain (https://your-domain.FAKE_TLD)format is not valid\n`, + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); - test("domain with not allowed characters should not be acceptable", () => { - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); + test("domain with not allowed characters should not be acceptable", () => { + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); - const domain = "your!domain.com"; + const domain = "your!domain.com"; - expect(() => { validateDomain(domain); }).toThrow(); + expect(() => { + validateDomain(domain); + }).toThrow(); - expect(shell.echo).toBeCalledWith("\n[Error] - Domain (https://your!domain.com)format is not valid\n"); - expect(shell.exit).toHaveBeenCalledWith(1); - }); - }); + expect(shell.echo).toBeCalledWith( + "\n[Error] - Domain (https://your!domain.com)format is not valid\n", + ); + expect(shell.exit).toHaveBeenCalledWith(1); + }); + }); - describe("corrent domains", () => { - const domains = [ - ["your-domain.com"], - ["local.your-domain.com"], - ["your-domain.local"], - ["foo.your-domain.local"], - ["your-domain.test"], - ["foo.your-domain.local"], - ]; + describe("corrent domains", () => { + const domains = [ + ["your-domain.com"], + ["local.your-domain.com"], + ["your-domain.local"], + ["foo.your-domain.local"], + ["your-domain.test"], + ["foo.your-domain.local"], + ]; - test.each(domains)("domain %s is acceptable", (domain) => { - validateDomain(domain); + test.each(domains)("domain %s is acceptable", (domain) => { + validateDomain(domain); - expect(shell.echo).not.toBeCalled(); - expect(shell.exit).not.toHaveBeenCalledWith(1); - }); - }); + expect(shell.echo).not.toBeCalled(); + expect(shell.exit).not.toHaveBeenCalledWith(1); + }); + }); }); diff --git a/packages/cli/src/utils/validate-domain.ts b/packages/cli/src/utils/validate-domain.ts index 2209403..8219c24 100644 --- a/packages/cli/src/utils/validate-domain.ts +++ b/packages/cli/src/utils/validate-domain.ts @@ -3,21 +3,23 @@ import isUrlHttp from "is-url-http"; import shell from "shelljs"; const validateDomain = (value: string) => { - const domains = value.split(",").map(d => `https://${d.trim()}`); + const domains = value.split(",").map((d) => `https://${d.trim()}`); - domains.forEach((domainItem) => { - let domain = domainItem; + domains.forEach((domainItem) => { + let domain = domainItem; - // include validate domains like .local or .test - if (/\.local$|\.test$/g.test(domainItem)) { - domain = domain.replace(/\.local$|\.test$/, ".com"); - } + // include validate domains like .local or .test + if (/\.local$|\.test$/g.test(domainItem)) { + domain = domain.replace(/\.local$|\.test$/, ".com"); + } - if (!isUrlHttp(domain)) { - shell.echo(chalk.red(`\n[Error] - Domain (${domainItem})format is not valid\n`)); - shell.exit(1); - } - }); + if (!isUrlHttp(domain)) { + shell.echo( + chalk.red(`\n[Error] - Domain (${domainItem})format is not valid\n`), + ); + shell.exit(1); + } + }); }; -export default validateDomain; \ No newline at end of file +export default validateDomain; diff --git a/packages/cli/src/utils/validate-location.ts b/packages/cli/src/utils/validate-location.ts index 1251d80..dd3284d 100644 --- a/packages/cli/src/utils/validate-location.ts +++ b/packages/cli/src/utils/validate-location.ts @@ -1,9 +1,7 @@ const validateLocation = (location: string) => { - if (!location.startsWith("/")) { - throw new Error("Location should start by /"); - } + if (!location.startsWith("/")) { + throw new Error("Location should start by /"); + } +}; - -} - -export default validateLocation; \ No newline at end of file +export default validateLocation; diff --git a/packages/cli/src/utils/validate-port.test.ts b/packages/cli/src/utils/validate-port.test.ts index b05ef3a..9abde04 100644 --- a/packages/cli/src/utils/validate-port.test.ts +++ b/packages/cli/src/utils/validate-port.test.ts @@ -2,53 +2,52 @@ import shell from "shelljs"; import validatePort from "./validate-port"; -vi.mock('shelljs'); +vi.mock("shelljs"); vi.mock("chalk", async () => ({ - default: { - green: vi.fn((v) => v), - red: vi.fn((v) => v) - } + default: { + green: vi.fn((v) => v), + red: vi.fn((v) => v), + }, })); describe("Validate port", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe("valid", () => { - const ports = [ - ["1025"], - ["3000"], - ["65535"], - ]; - test.each(ports)("Port %s is valid", (port) => { - validatePort(Number(port)); - - expect(shell.echo).not.toBeCalled(); - expect(shell.exit).not.toHaveBeenCalledWith(1); - }); - }); - - describe("invalid (port should be from 1025 to 65535", () => { - const ports = [ - ["foo"], - ["333"], - ["1024"], - ["70000"], - ]; - - test.each(ports)("Port %s is not valid", (port) => { - vi.spyOn(shell, 'exit').mockImplementation(() => { throw new Error(); }); - - expect(() => { validatePort(Number(port)); }).toThrow(); - - if (Number(port)) { - expect(shell.echo).toBeCalledWith("\n[Error] - Port (--port ) should be into the range 1025 to 65535\n"); - } else { - expect(shell.echo).toBeCalledWith("\n[Error] - Port (--port ) should be a valid number\n"); - } - expect(shell.exit).toHaveBeenCalledWith(1); - }); - }); + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("valid", () => { + const ports = [["1025"], ["3000"], ["65535"]]; + test.each(ports)("Port %s is valid", (port) => { + validatePort(Number(port)); + + expect(shell.echo).not.toBeCalled(); + expect(shell.exit).not.toHaveBeenCalledWith(1); + }); + }); + + describe("invalid (port should be from 1025 to 65535", () => { + const ports = [["foo"], ["333"], ["1024"], ["70000"]]; + + test.each(ports)("Port %s is not valid", (port) => { + vi.spyOn(shell, "exit").mockImplementation(() => { + throw new Error(); + }); + + expect(() => { + validatePort(Number(port)); + }).toThrow(); + + if (Number(port)) { + expect(shell.echo).toBeCalledWith( + "\n[Error] - Port (--port ) should be into the range 1025 to 65535\n", + ); + } else { + expect(shell.echo).toBeCalledWith( + "\n[Error] - Port (--port ) should be a valid number\n", + ); + } + expect(shell.exit).toHaveBeenCalledWith(1); + }); + }); }); diff --git a/packages/cli/src/utils/validate-port.ts b/packages/cli/src/utils/validate-port.ts index b764de5..0ac26c8 100644 --- a/packages/cli/src/utils/validate-port.ts +++ b/packages/cli/src/utils/validate-port.ts @@ -2,19 +2,23 @@ import chalk from "chalk"; import shell from "shelljs"; const validatePort = (port: string) => { - const portIsNumber = !isNaN(Number(port)); - if (!portIsNumber) { - shell.echo(chalk.red("\n[Error] - Port (--port ) should be a valid number\n")); - shell.exit(1); - } + const portIsNumber = !isNaN(Number(port)); + if (!portIsNumber) { + shell.echo( + chalk.red("\n[Error] - Port (--port ) should be a valid number\n"), + ); + shell.exit(1); + } - const portIsValid = Number(port) > 1024 && Number(port) <= 65535; - if (!portIsValid) { - shell.echo( - chalk.red("\n[Error] - Port (--port ) should be into the range 1025 to 65535\n") - ); - shell.exit(1); - } -} + const portIsValid = Number(port) > 1024 && Number(port) <= 65535; + if (!portIsValid) { + shell.echo( + chalk.red( + "\n[Error] - Port (--port ) should be into the range 1025 to 65535\n", + ), + ); + shell.exit(1); + } +}; -export default validatePort; \ No newline at end of file +export default validatePort; diff --git a/packages/cli/vite.config.ts b/packages/cli/vite.config.ts index ffa0906..2634971 100644 --- a/packages/cli/vite.config.ts +++ b/packages/cli/vite.config.ts @@ -1,17 +1,17 @@ -import { resolve } from 'path'; -import { defineConfig } from 'vite' -import dts from 'vite-plugin-dts'; +import { resolve } from "path"; +import { defineConfig } from "vite"; +import dts from "vite-plugin-dts"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [dts({ include: ["src"] })], - build: { - lib: { - entry: resolve(__dirname, 'src/index.ts'), - name: 'index', - fileName: 'index', - formats: ["cjs", "es", "umd"], - }, - ssr: true - }, + plugins: [dts({ include: ["src"] })], + build: { + lib: { + entry: resolve(__dirname, "src/index.ts"), + name: "index", + fileName: "index", + formats: ["cjs", "es", "umd"], + }, + ssr: true, + }, }); diff --git a/packages/cli/vitest.config.ts b/packages/cli/vitest.config.ts index cb9c2ad..4d81897 100644 --- a/packages/cli/vitest.config.ts +++ b/packages/cli/vitest.config.ts @@ -1,14 +1,14 @@ -import path from 'path'; -import { defineConfig } from 'vitest/config'; +import path from "path"; +import { defineConfig } from "vitest/config"; export default defineConfig({ - test: { - globals: true, - environment: 'node', - }, - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, + test: { + globals: true, + environment: "node", + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, }); diff --git a/yarn.lock b/yarn.lock index 7fd9814..5427be9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@alloc/quick-lru@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" @@ -524,7 +529,7 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.4.tgz#2562ce6dfd48c15a80b8daa2e38cce5b50573624" integrity sha512-qJr3wVvcLjPFcV4AMDS3iquhBfTef2zo/jlm8RMxmiRp3Vy2HY8WMxrykJlcbCnqLXZPA0YZxZGND6eug85ogg== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== @@ -536,6 +541,11 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + "@eslint/eslintrc@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" @@ -551,11 +561,31 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + "@eslint/js@8.43.0": version "8.43.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.43.0.tgz#559ca3d9ddbd6bf907ad524320a0d14b85586af0" integrity sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg== +"@eslint/js@8.56.0": + version "8.56.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" + integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== + "@fontsource/fira-mono@^4.5.10": version "4.5.10" resolved "https://registry.yarnpkg.com/@fontsource/fira-mono/-/fira-mono-4.5.10.tgz#443be4b2b4fc6e685b88431fcfdaf8d5f5639bbf" @@ -570,6 +600,15 @@ debug "^4.1.1" minimatch "^3.0.5" +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== + dependencies: + "@humanwhocodes/object-schema" "^2.0.1" + debug "^4.1.1" + minimatch "^3.0.5" + "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" @@ -580,6 +619,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -907,11 +951,46 @@ dependencies: semver "^7.3.5" +"@oxlint/darwin-arm64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/darwin-arm64/-/darwin-arm64-0.0.22.tgz#6c8766f375b1954032379229fff130878e81fe20" + integrity sha512-n8ZsnApsKKxho00fYR+EzOEt6dVcuMfwdOwoAwpWwdIwrJRUyjWDzZhauX1VGEmgf4Hzm2y53aJMSZAWnIbr7g== + +"@oxlint/darwin-x64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/darwin-x64/-/darwin-x64-0.0.22.tgz#2c8091eb722d9ee186c8a47d8be392fc917974f3" + integrity sha512-glVFfh5OtpeqfW2xGf47LPZxByvoodQKQF9Y3ql6HVNHzpUNSDsacO/5hyQ585FiKG3OtFlOP8TaeeDCcj+pXQ== + +"@oxlint/linux-arm64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/linux-arm64/-/linux-arm64-0.0.22.tgz#951cfc224f11b3100036f09d15d9fb790cce5c8d" + integrity sha512-01B8IEMQBFXGabcqLJXxiaT5eTqjO6eNJTl9HwaGJsTlDIxfbE0wPGWJz1POuvTDHDp+IjAR+NjuCwgikWpzbg== + +"@oxlint/linux-x64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/linux-x64/-/linux-x64-0.0.22.tgz#201299b65a2a9a768348943e801da2105401585c" + integrity sha512-pR9G7yt6RuZMgahe/fAl+TN4hgKZ60qfktwgMn5aLZAufE3fVEg83KncJtFwE++gTiG+xZ8qReYPjEWlI7a7cQ== + +"@oxlint/win32-arm64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/win32-arm64/-/win32-arm64-0.0.22.tgz#782cad274ee69d934ca458bf9026a3da3dc69228" + integrity sha512-R/uejrBLO4uQw+jbyusn1LwNTHasZCeiFa/zmP31CRlgD/tUwTYGpERLkpGRmvlzwf8UeFOxyRibNLzz4pXpxA== + +"@oxlint/win32-x64@0.0.22": + version "0.0.22" + resolved "https://registry.yarnpkg.com/@oxlint/win32-x64/-/win32-x64-0.0.22.tgz#89a50b37afe60caa9c0692c993189a4f0a1ea50d" + integrity sha512-g4mY10w/oFJUE6lc8F0IiU5LTEKcqxmY4vdmPLQZa2FoM8d2Rf+lLdbiaL9xouF8Zlp8mUyEgWHasKgN/wzLxw== + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@pkgr/core@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.0.tgz#7d8dacb7fdef0e4387caf7396cbd77f179867d06" + integrity sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ== + "@playwright/test@^1.28.1": version "1.35.1" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.35.1.tgz#a596b61e15b980716696f149cc7a2002f003580c" @@ -1214,11 +1293,21 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json-schema@^7.0.9": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + "@types/minimatch@*": version "5.1.2" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" @@ -1259,6 +1348,11 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== +"@types/semver@^7.5.0": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + "@types/shelljs@^0.8.12": version "0.8.12" resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.12.tgz#79dc9632af7d5ca1b5afb65a6bfc1422d79b5fa0" @@ -1300,6 +1394,23 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@^6.17.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz#94b86f3c25b468c714a04bd490017ecec2fd3746" + integrity sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/type-utils" "6.18.0" + "@typescript-eslint/utils" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/parser@^5.45.0": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.11.tgz#af7d4b7110e3068ce0b97550736de455e4250103" @@ -1310,6 +1421,17 @@ "@typescript-eslint/typescript-estree" "5.59.11" debug "^4.3.4" +"@typescript-eslint/parser@^6.17.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.18.0.tgz#d494161d64832e869f0a6acc6000a2cdff858383" + integrity sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA== + dependencies: + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/typescript-estree" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz#5d131a67a19189c42598af9fb2ea1165252001ce" @@ -1318,6 +1440,14 @@ "@typescript-eslint/types" "5.59.11" "@typescript-eslint/visitor-keys" "5.59.11" +"@typescript-eslint/scope-manager@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz#24ca6fc1f4a2afa71122dcfca9282878687d9997" + integrity sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA== + dependencies: + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + "@typescript-eslint/type-utils@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz#5eb67121808a84cb57d65a15f48f5bdda25f2346" @@ -1328,11 +1458,26 @@ debug "^4.3.4" tsutils "^3.21.0" +"@typescript-eslint/type-utils@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz#a492da599da5c38c70aa9ff9bfb473961b8ae663" + integrity sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ== + dependencies: + "@typescript-eslint/typescript-estree" "6.18.0" + "@typescript-eslint/utils" "6.18.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.11.tgz#1a9018fe3c565ba6969561f2a49f330cf1fe8db1" integrity sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA== +"@typescript-eslint/types@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.18.0.tgz#ffce610a1540c17cf7d8ecf2bb34b8b0e2e77101" + integrity sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA== + "@typescript-eslint/typescript-estree@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz#b2caaa31725e17c33970c1197bcd54e3c5f42b9f" @@ -1346,6 +1491,20 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz#1c357c3ca435c3cfa2af6b9daf45ca0bc2bb059a" + integrity sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg== + dependencies: + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.11.tgz#9dbff49dc80bfdd9289f9f33548f2e8db3c59ba1" @@ -1360,6 +1519,19 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.18.0.tgz#4d07c9c08f84b9939a1aca7aef98c8f378936142" + integrity sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/typescript-estree" "6.18.0" + semver "^7.5.4" + "@typescript-eslint/visitor-keys@5.59.11": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz#dca561ddad169dc27d62396d64f45b2d2c3ecc56" @@ -1368,6 +1540,19 @@ "@typescript-eslint/types" "5.59.11" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@6.18.0": + version "6.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz#3c8733737786fa6c78a347b4fa306ae7155b560f" + integrity sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA== + dependencies: + "@typescript-eslint/types" "6.18.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@vercel/ncc@^0.36.1": version "0.36.1" resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.36.1.tgz#d4c01fdbbe909d128d1bf11c7f8b5431654c5b95" @@ -1454,6 +1639,11 @@ acorn@^8.8.0, acorn@^8.8.1, acorn@^8.8.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59" integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== +acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1580,11 +1770,74 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + array-union@^2.1.0: version "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.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -1612,6 +1865,11 @@ autoprefixer@^10.4.14: picocolors "^1.0.0" postcss-value-parser "^4.2.0" +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + babel-jest@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" @@ -1771,6 +2029,15 @@ cacache@^17.0.0: tar "^6.1.11" unique-filename "^3.0.0" +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2110,6 +2377,13 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, d dependencies: ms "2.1.2" +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" @@ -2150,6 +2424,24 @@ deepmerge@^4.2.2, deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2197,6 +2489,13 @@ dlv@^1.1.3: resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -2253,11 +2552,81 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + es-module-lexer@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + es6-promise@^3.1.2: version "3.3.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" @@ -2349,6 +2718,63 @@ eslint-config-prettier@^8.5.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +eslint-plugin-prettier@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.2.tgz#584c94d4bf31329b2d4cbeb10fd600d17d6de742" + integrity sha512-dhlpWc9vOwohcWmClFcA+HjlvUpuyynYs0Rf+L/P6/0iQE6vlHW9l5bkfzN62/Stm9fbq8ku46qzde76T1xlSg== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.6" + +eslint-plugin-simple-import-sort@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz#cc4ceaa81ba73252427062705b64321946f61351" + integrity sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw== + eslint-plugin-svelte@^2.26.0: version "2.30.0" resolved "https://registry.yarnpkg.com/eslint-plugin-svelte/-/eslint-plugin-svelte-2.30.0.tgz#548f77441c5418cc0063d36cf139970d6a2cefad" @@ -2380,11 +2806,24 @@ eslint-scope@^7.0.0, eslint-scope@^7.2.0: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + eslint@^8.28.0: version "8.43.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.43.0.tgz#3e8c6066a57097adfd9d390b8fc93075f257a094" @@ -2430,6 +2869,50 @@ eslint@^8.28.0: strip-json-comments "^3.1.0" text-table "^0.2.0" +eslint@^8.56.0: + version "8.56.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" + integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.56.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + esm-env@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.0.0.tgz#b124b40b180711690a4cb9b00d16573391950413" @@ -2444,6 +2927,15 @@ espree@^9.0.0, espree@^9.5.2: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -2524,7 +3016,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.2.0: +fast-diff@^1.1.2, fast-diff@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== @@ -2632,6 +3124,13 @@ flowbite@^1.6.5: "@popperjs/core" "^2.9.3" mini-svg-data-uri "^1.4.3" +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" @@ -2699,6 +3198,26 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + gauge@^4.0.3: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -2728,6 +3247,16 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -2738,6 +3267,14 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -2810,6 +3347,13 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -2833,6 +3377,13 @@ globby@^13.1.1, globby@^13.1.4: merge2 "^1.4.1" slash "^4.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -2853,6 +3404,11 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2863,6 +3419,30 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -2875,6 +3455,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hosted-git-info@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" @@ -2933,6 +3520,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2992,6 +3584,15 @@ install-artifact-from-github@^1.3.3: resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.3.3.tgz#57d89bacfa0f47d7307fe41b6247cda9f9a8079c" integrity sha512-x79SL0d8WOi1ZjXSTUqqs0GPQZ92YArJAN9O46wgU9wdH2U9ecyyhB9YGDbPe2OLV4ptmt6AZYRQZ2GydQZosQ== +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -3007,11 +3608,27 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3019,6 +3636,14 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-builtin-module@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -3026,6 +3651,11 @@ is-builtin-module@^3.2.1: dependencies: builtin-modules "^3.3.0" +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.5.0: version "2.12.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" @@ -3033,6 +3663,20 @@ is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.5.0: dependencies: has "^1.0.3" +is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3065,6 +3709,18 @@ is-module@^1.0.0: resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -3087,11 +3743,47 @@ is-reference@1.2.1: dependencies: "@types/estree" "*" +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-url-http@^2.3.5: version "2.3.5" resolved "https://registry.yarnpkg.com/is-url-http/-/is-url-http-2.3.5.tgz#4bfe9e6ff56f1d225de3490e05529634a03972c6" @@ -3099,6 +3791,18 @@ is-url-http@^2.3.5: dependencies: url-http "~1.0.2" +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -3571,6 +4275,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + json5@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -3849,6 +4560,13 @@ mini-svg-data-uri@^1.4.3: resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -3997,7 +4715,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4136,6 +4854,54 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -4162,6 +4928,30 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +oxlint@^0.0.22: + version "0.0.22" + resolved "https://registry.yarnpkg.com/oxlint/-/oxlint-0.0.22.tgz#61db77cec45c34d51249b410d2d83aec8de0e467" + integrity sha512-ZV9pmXiNdY9CHkDcceJ8bpo05HfgLb2nC6wlGcQeUktHpX8ASHgWM2fuw4fEPhhWsydy2lmdiNkw55CCw6S2+g== + optionalDependencies: + "@oxlint/darwin-arm64" "0.0.22" + "@oxlint/darwin-x64" "0.0.22" + "@oxlint/linux-arm64" "0.0.22" + "@oxlint/linux-x64" "0.0.22" + "@oxlint/win32-arm64" "0.0.22" + "@oxlint/win32-x64" "0.0.22" + p-event@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" @@ -4436,6 +5226,13 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + prettier-plugin-svelte@^2.8.1: version "2.10.1" resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.10.1.tgz#e1abbe5689e8a926c60b8bc42e61233556ca90d1" @@ -4446,6 +5243,11 @@ prettier@^2.8.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" + integrity sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw== + pretty-format@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" @@ -4576,6 +5378,15 @@ redent@^4.0.0: indent-string "^5.0.0" strip-indent "^4.0.0" +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -4612,6 +5423,15 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22. path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@~1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" @@ -4672,11 +5492,30 @@ sade@^1.7.4, sade@^1.8.1: dependencies: mri "^1.1.0" +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -4697,6 +5536,11 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2: version "7.5.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" @@ -4704,6 +5548,13 @@ semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2: dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + semver@~7.3.0: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" @@ -4721,6 +5572,25 @@ set-cookie-parser@^2.6.0: resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4742,6 +5612,15 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + siginfo@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" @@ -4922,6 +5801,33 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -4943,6 +5849,11 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -5062,6 +5973,14 @@ svelte@^3.54.0: resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.59.1.tgz#3de3d56b9165748f32f3131589b8d183cabe7449" integrity sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ== +synckit@^0.8.6: + version "0.8.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + tailwindcss@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3" @@ -5193,6 +6112,11 @@ trim-newlines@^4.0.2: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125" integrity sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ== +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" @@ -5206,6 +6130,16 @@ ts-morph@18.0.0: "@ts-morph/common" "~0.19.0" code-block-writer "^12.0.0" +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -5216,6 +6150,11 @@ tslib@^2.4.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -5250,6 +6189,45 @@ type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typescript@^5.0.0, typescript@^5.0.3, typescript@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" @@ -5265,6 +6243,16 @@ ufo@^1.1.2: resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76" integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ== +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + undici@~5.22.0: version "5.22.1" resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" @@ -5493,6 +6481,28 @@ well-known-symbols@^2.0.0: resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-2.0.0.tgz#e9c7c07dbd132b7b84212c8174391ec1f9871ba5" integrity sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q== +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"