diff --git a/packages/cli/.eslintrc b/packages/cli/.eslintrc new file mode 100644 index 0000000..35cfb79 --- /dev/null +++ b/packages/cli/.eslintrc @@ -0,0 +1,9 @@ +{ + "root": true, + "extends": [ + "lxsmnsyc/typescript" + ], + "parserOptions": { + "project": "./tsconfig.eslint.json" + } +} diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore new file mode 100644 index 0000000..53992de --- /dev/null +++ b/packages/cli/.gitignore @@ -0,0 +1,107 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.production +.env.development + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +.npmrc diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 0000000..c5004dd --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,72 @@ +{ + "name": "@modal-sh/cli", + "version": "0.0.0", + "files": [ + "dist", + "src" + ], + "engines": { + "node": ">=12" + }, + "license": "UNLICENSED", + "keywords": [ + "pridepack" + ], + "devDependencies": { + "@types/node": "^18.14.1", + "@types/yargs": "^17.0.24", + "eslint": "^8.35.0", + "eslint-config-lxsmnsyc": "^0.5.0", + "pridepack": "2.4.4", + "tslib": "^2.5.0", + "typescript": "^4.9.5", + "vitest": "^0.28.1" + }, + "scripts": { + "prepublishOnly": "pridepack clean && pridepack build", + "build": "pridepack build", + "type-check": "pridepack check", + "lint": "pridepack lint", + "clean": "pridepack clean", + "watch": "pridepack watch", + "start": "pridepack start", + "dev": "pridepack dev", + "test": "vitest" + }, + "private": true, + "description": "CLI app.", + "repository": { + "url": "", + "type": "git" + }, + "homepage": "", + "bugs": { + "url": "" + }, + "author": "TheoryOfNekomata ", + "publishConfig": { + "access": "restricted" + }, + "types": "./dist/types/index.d.ts", + "main": "./dist/cjs/production/index.js", + "module": "./dist/esm/production/index.js", + "exports": { + ".": { + "development": { + "require": "./dist/cjs/development/index.js", + "import": "./dist/esm/development/index.js" + }, + "require": "./dist/cjs/production/index.js", + "import": "./dist/esm/production/index.js", + "types": "./dist/types/index.d.ts" + } + }, + "typesVersions": { + "*": {} + }, + "dependencies": { + "@clack/core": "^0.3.2", + "@modal-sh/core": "workspace:*", + "yargs": "^17.7.2" + } +} diff --git a/packages/cli/pridepack.json b/packages/cli/pridepack.json new file mode 100644 index 0000000..841fb58 --- /dev/null +++ b/packages/cli/pridepack.json @@ -0,0 +1,3 @@ +{ + "target": "es2018" +} \ No newline at end of file diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts new file mode 100644 index 0000000..79e7082 --- /dev/null +++ b/packages/cli/src/cli.ts @@ -0,0 +1,5 @@ +import yargs from 'yargs'; + +export const createCli = (argv: typeof process.argv) => { + return yargs(argv); +}; diff --git a/packages/cli/src/commands.ts b/packages/cli/src/commands.ts new file mode 100644 index 0000000..7eaf8ae --- /dev/null +++ b/packages/cli/src/commands.ts @@ -0,0 +1,15 @@ +import yargs from 'yargs'; +import { AdderController, AdderControllerImpl } from './modules/adder'; + +export const addCommands = (cli: yargs.Argv) => { + const adderController: AdderController = new AdderControllerImpl(); + + cli.command({ + aliases: ['a'], + command: 'add ', + describe: 'Add two numbers', + handler: adderController.addNumbers, + }); + + return cli; +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts new file mode 100644 index 0000000..2ce560d --- /dev/null +++ b/packages/cli/src/index.ts @@ -0,0 +1,9 @@ +import { addCommands } from '@/commands'; +import { createCli } from '@/cli'; +import { hideBin } from 'yargs/helpers'; + +const args = createCli(hideBin(process.argv)); + +addCommands(args); + +args.parse(); diff --git a/packages/cli/src/modules/adder/adder.controller.ts b/packages/cli/src/modules/adder/adder.controller.ts new file mode 100644 index 0000000..dba879c --- /dev/null +++ b/packages/cli/src/modules/adder/adder.controller.ts @@ -0,0 +1,42 @@ +import { ArgumentsCamelCase } from 'yargs'; +import { + AdderService, + AdderServiceImpl, + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +} from './adder.service'; + +export interface AdderController { + addNumbers: (args: ArgumentsCamelCase<{ a: number, b: number }>) => void | Promise; +} + +export class AdderControllerImpl implements AdderController { + constructor( + private readonly adderService: AdderService = new AdderServiceImpl(), + ) { + // noop + } + + readonly addNumbers = async (args: ArgumentsCamelCase<{ a: number, b: number }>) => { + const { a, b } = args; + try { + const response = this.adderService.addNumbers({a, b}); + process.stdout.write(`${response}\n`); + process.exit(0); + } catch (errorRaw) { + const error = errorRaw as Error; + if (error instanceof InvalidArgumentTypeError) { + process.stderr.write(`${error.message}\n`); + process.exit(-1); + return; + } + if (error instanceof ArgumentOutOfRangeError) { + process.stderr.write(`${error.message}\n`); + process.exit(-2); + return; + } + process.stderr.write(`${error.message}\n`); + process.exit(-3); + } + } +} diff --git a/packages/cli/src/modules/adder/adder.service.ts b/packages/cli/src/modules/adder/adder.service.ts new file mode 100644 index 0000000..144cfd3 --- /dev/null +++ b/packages/cli/src/modules/adder/adder.service.ts @@ -0,0 +1,21 @@ +import { + add, + AddFunctionOptions, + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +} from '@modal-sh/core'; + +export interface AdderService { + addNumbers(options: AddFunctionOptions): number; +} + +export class AdderServiceImpl implements AdderService { + addNumbers(options: AddFunctionOptions) { + return add(options); + } +} + +export { + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +}; diff --git a/packages/cli/src/modules/adder/index.ts b/packages/cli/src/modules/adder/index.ts new file mode 100644 index 0000000..4f40b37 --- /dev/null +++ b/packages/cli/src/modules/adder/index.ts @@ -0,0 +1,2 @@ +export * from './adder.controller'; +export * from './adder.service'; diff --git a/packages/cli/test/index.test.ts b/packages/cli/test/index.test.ts new file mode 100644 index 0000000..33c0af2 --- /dev/null +++ b/packages/cli/test/index.test.ts @@ -0,0 +1,64 @@ +import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest'; + +import { createCli } from '../src/cli'; +import { addCommands } from '../src/commands'; +import yargs from 'yargs'; +import { AdderServiceImpl, InvalidArgumentTypeError, ArgumentOutOfRangeError } from '../src/modules/adder'; + +vi.mock('process'); + +describe('blah', () => { + let cli: yargs.Argv; + let exit: vi.Mock; + let exitReal: typeof process.exit; + + beforeAll(() => { + exitReal = process.exit.bind(process); + const processMut = process as unknown as Record; + processMut.exit = exit = vi.fn(); + }); + + afterAll(() => { + process.exit = exitReal = process.exit.bind(process); + }); + + it('returns result when successful', async () => { + cli = createCli(['add', '1', '2']); + addCommands(cli); + await cli.parse(); + expect(exit).toHaveBeenCalledWith(0); + }); + + it('returns error when given invalid inputs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new InvalidArgumentTypeError('Invalid input'); + }); + + cli = createCli(['add', '1', '2']); + addCommands(cli); + await cli.parse(); + expect(exit).toHaveBeenCalledWith(-1); + }); + + it('returns error when given out-of-range inputs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new ArgumentOutOfRangeError('Out of range'); + }); + + cli = createCli(['add', '1', '2']); + addCommands(cli); + await cli.parse(); + expect(exit).toHaveBeenCalledWith(-2); + }); + + it('returns error when an unexpected error occurs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new Error('Unexpected error'); + }); + + cli = createCli(['add', '1', '2']); + addCommands(cli); + await cli.parse(); + expect(exit).toHaveBeenCalledWith(-2); + }); +}); diff --git a/packages/cli/tsconfig.eslint.json b/packages/cli/tsconfig.eslint.json new file mode 100644 index 0000000..479db12 --- /dev/null +++ b/packages/cli/tsconfig.eslint.json @@ -0,0 +1,24 @@ +{ + "exclude": ["node_modules"], + "include": ["src", "types", "test"], + "compilerOptions": { + "module": "ESNext", + "lib": ["ESNext"], + "importHelpers": true, + "declaration": true, + "sourceMap": true, + "rootDir": "./", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", + "jsx": "react", + "esModuleInterop": true, + "target": "es2018", + "paths": { + "@/*": ["./src/*"], + } + } +} diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 0000000..746acb5 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,24 @@ +{ + "exclude": ["node_modules"], + "include": ["src", "types"], + "compilerOptions": { + "module": "ESNext", + "lib": ["ESNext"], + "importHelpers": true, + "declaration": true, + "sourceMap": true, + "rootDir": "./src", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", + "jsx": "react", + "esModuleInterop": true, + "target": "es2018", + "paths": { + "@/*": ["./src/*"], + } + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ce0e7a9..feea61e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -7,16 +7,27 @@ export interface AddFunction { (options: AddFunctionOptions): number; } +export class InvalidArgumentTypeError extends TypeError { + constructor(message: string) { + super(message); + this.name = 'InvalidArgumentTypeError'; + } +} + +export class ArgumentOutOfRangeError extends RangeError { + constructor(message: string) { + super(message); + this.name = 'ArgumentOutOfRangeError'; + } +} + export const add: AddFunction = (options: AddFunctionOptions): number => { - if (process.env.NODE_ENV !== 'production') { - console.log('This code would not appear on production builds'); - } const { a, b } = options as unknown as Record; if (typeof a !== 'number' || typeof b !== 'number') { - throw new TypeError('a and b must be numbers'); + throw new InvalidArgumentTypeError('a and b must be numbers'); } if (!Number.isFinite(a) || !Number.isFinite(b)) { - throw new RangeError('a and b must be finite numbers'); + throw new ArgumentOutOfRangeError('a and b must be finite numbers'); } return a + b; diff --git a/packages/core/test/index.test.ts b/packages/core/test/index.test.ts index 5697ef7..b25378d 100644 --- a/packages/core/test/index.test.ts +++ b/packages/core/test/index.test.ts @@ -2,7 +2,15 @@ import { describe, it, expect } from 'vitest'; import { add } from '../src'; describe('blah', () => { - it('works', () => { + it('returns result', () => { expect(add({ a: 1, b: 1 })).toEqual(2); }); + + it('throws when given invalid argument types', () => { + expect(() => add({ a: '1' as unknown as number, b: 1 })).toThrow(TypeError); + }); + + it('throws when given out-of-range arguments', () => { + expect(() => add({ a: Infinity, b: 1 })).toThrow(RangeError); + }); }); diff --git a/packages/web-api/package.json b/packages/web-api/package.json index 29305ca..b1b7f0e 100644 --- a/packages/web-api/package.json +++ b/packages/web-api/package.json @@ -50,5 +50,22 @@ "author": "TheoryOfNekomata ", "publishConfig": { "access": "restricted" - } + }, + "types": "./dist/types/index.d.ts", + "main": "./dist/cjs/production/index.js", + "module": "./dist/esm/production/index.js", + "exports": { + ".": { + "development": { + "require": "./dist/cjs/development/index.js", + "import": "./dist/esm/development/index.js" + }, + "require": "./dist/cjs/production/index.js", + "import": "./dist/esm/production/index.js", + "types": "./dist/types/index.d.ts" + } + }, + "typesVersions": { + "*": {} + } } diff --git a/packages/web-api/src/config.ts b/packages/web-api/src/config.ts index 18aa9ac..11d4fa4 100644 --- a/packages/web-api/src/config.ts +++ b/packages/web-api/src/config.ts @@ -1,5 +1,6 @@ export namespace meta { export const host = process.env.HOST ?? '0.0.0.0'; + export const port = Number(process.env.PORT ?? 8080); export const env = process.env.NODE_ENV ?? 'development'; diff --git a/packages/web-api/src/index.ts b/packages/web-api/src/index.ts index c9b2b74..bdcc8c4 100644 --- a/packages/web-api/src/index.ts +++ b/packages/web-api/src/index.ts @@ -2,10 +2,8 @@ import { createServer } from '@/server'; import { addRoutes } from '@/routes'; import * as config from '@/config'; -const logger = config.meta.env !== 'test'; - const server = createServer({ - logger, + logger: config.meta.env !== 'test', }); addRoutes(server); diff --git a/packages/web-api/src/modules/adder/adder.controller.ts b/packages/web-api/src/modules/adder/adder.controller.ts new file mode 100644 index 0000000..aaa4f56 --- /dev/null +++ b/packages/web-api/src/modules/adder/adder.controller.ts @@ -0,0 +1,39 @@ +import { RouteHandlerMethod } from 'fastify'; +import { + AdderService, + AdderServiceImpl, + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +} from '@/modules/adder/adder.service'; +import { constants } from 'http2'; + +export interface AdderController { + addNumbers: RouteHandlerMethod; +} + +export class AdderControllerImpl implements AdderController { + constructor( + private readonly adderService: AdderService = new AdderServiceImpl(), + ) { + // noop + } + + readonly addNumbers: RouteHandlerMethod = async (request, reply) => { + const { a, b } = request.body as { a: number; b: number }; + try { + const response = this.adderService.addNumbers({a, b}); + reply.send(response); + } catch (errorRaw) { + if (errorRaw instanceof InvalidArgumentTypeError) { + reply.status(constants.HTTP_STATUS_BAD_REQUEST).send(errorRaw.message); + return; + } + if (errorRaw instanceof ArgumentOutOfRangeError) { + reply.status(constants.HTTP_STATUS_BAD_REQUEST).send(errorRaw.message); + return; + } + const error = errorRaw as Error; + reply.status(constants.HTTP_STATUS_INTERNAL_SERVER_ERROR).send(error.message); + } + } +} diff --git a/packages/web-api/src/modules/adder/adder.service.ts b/packages/web-api/src/modules/adder/adder.service.ts new file mode 100644 index 0000000..144cfd3 --- /dev/null +++ b/packages/web-api/src/modules/adder/adder.service.ts @@ -0,0 +1,21 @@ +import { + add, + AddFunctionOptions, + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +} from '@modal-sh/core'; + +export interface AdderService { + addNumbers(options: AddFunctionOptions): number; +} + +export class AdderServiceImpl implements AdderService { + addNumbers(options: AddFunctionOptions) { + return add(options); + } +} + +export { + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +}; diff --git a/packages/web-api/src/modules/adder/index.ts b/packages/web-api/src/modules/adder/index.ts new file mode 100644 index 0000000..4f40b37 --- /dev/null +++ b/packages/web-api/src/modules/adder/index.ts @@ -0,0 +1,2 @@ +export * from './adder.controller'; +export * from './adder.service'; diff --git a/packages/web-api/src/routes.ts b/packages/web-api/src/routes.ts index eadfdc0..8140ec9 100644 --- a/packages/web-api/src/routes.ts +++ b/packages/web-api/src/routes.ts @@ -1,22 +1,13 @@ import { FastifyInstance } from 'fastify'; -import { add, AddFunctionOptions } from '@modal-sh/core'; +import { AdderController, AdderControllerImpl } from '@/modules/adder'; export const addRoutes = (server: FastifyInstance) => { - server.post('/', async (request, reply) => { - const { a, b } = request.body as AddFunctionOptions; - try { - const response = add({a, b}); - reply.send(response); - } catch (errorRaw) { - if (errorRaw instanceof TypeError) { - reply.status(400).send(errorRaw.message); - } else if (errorRaw instanceof RangeError) { - reply.status(400).send(errorRaw.message); - } else { - const error = errorRaw as Error; - reply.status(500).send(error.message); - } - } + const adderController: AdderController = new AdderControllerImpl(); + + server.route({ + method: 'POST', + url: '/', + handler: adderController.addNumbers, }); return server; diff --git a/packages/web-api/test/index.test.ts b/packages/web-api/test/index.test.ts index fef22e2..69c6a04 100644 --- a/packages/web-api/test/index.test.ts +++ b/packages/web-api/test/index.test.ts @@ -5,30 +5,83 @@ import { expect, beforeAll, afterAll, + vi, } from 'vitest'; +import { constants } from 'http2'; import { createServer } from '../src/server'; import { addRoutes } from '../src/routes'; +import { + AdderServiceImpl, + ArgumentOutOfRangeError, + InvalidArgumentTypeError, +} from '../src/modules/adder'; describe('Example', () => { - let SERVER: FastifyInstance; + let server: FastifyInstance; + const body = { a: 1, b: 2 }; beforeAll(() => { - SERVER = createServer(); - addRoutes(SERVER); + server = createServer(); + addRoutes(server); }); afterAll(async () => { - await SERVER.close(); + await server.close(); }); - it('should have the expected content', async () => { - const response = await SERVER + it('returns result when successful', async () => { + const response = await server .inject() .post('/') - .body({ a: 1, b: 2 }) + .body(body) .headers({ 'Accept': 'application/json', }); - expect(response.statusCode).toBe(200); + expect(response.statusCode).toBe(constants.HTTP_STATUS_OK); }); + + it('returns error when given invalid inputs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new InvalidArgumentTypeError('Invalid input'); + }); + + const response = await server + .inject() + .post('/') + .body(body) + .headers({ + 'Accept': 'application/json', + }); + expect(response.statusCode).toBe(constants.HTTP_STATUS_BAD_REQUEST); + }); + + it('returns error when given out-of-range inputs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new ArgumentOutOfRangeError('Out of range'); + }); + + const response = await server + .inject() + .post('/') + .body(body) + .headers({ + 'Accept': 'application/json', + }); + expect(response.statusCode).toBe(constants.HTTP_STATUS_BAD_REQUEST); + }); + + it('returns error when an unexpected error occurs', async () => { + vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { + throw new Error('Unexpected error'); + }); + + const response = await server + .inject() + .post('/') + .body({ a: 1, b: 2 }) + .headers({ + 'Accept': 'application/json', + }); + expect(response.statusCode).toBe(constants.HTTP_STATUS_INTERNAL_SERVER_ERROR); + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 31cf3e3..ac04070 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,43 @@ settings: importers: + packages/cli: + dependencies: + '@clack/core': + specifier: ^0.3.2 + version: 0.3.2 + '@modal-sh/core': + specifier: workspace:* + version: link:../core + yargs: + specifier: ^17.7.2 + version: 17.7.2 + devDependencies: + '@types/node': + specifier: ^18.14.1 + version: 18.14.1 + '@types/yargs': + specifier: ^17.0.24 + version: 17.0.24 + eslint: + specifier: ^8.35.0 + version: 8.35.0 + eslint-config-lxsmnsyc: + specifier: ^0.5.0 + version: 0.5.0(eslint@8.35.0)(typescript@4.9.5) + pridepack: + specifier: 2.4.4 + version: 2.4.4(eslint@8.35.0)(tslib@2.5.0)(typescript@4.9.5) + tslib: + specifier: ^2.5.0 + version: 2.5.0 + typescript: + specifier: ^4.9.5 + version: 4.9.5 + vitest: + specifier: ^0.28.1 + version: 0.28.1 + packages/core: devDependencies: '@types/node': @@ -332,6 +369,13 @@ packages: to-fast-properties: 2.0.0 dev: true + /@clack/core@0.3.2: + resolution: {integrity: sha512-FZnsNynwGDIDktx6PEZK1EuCkFpY4ldEX6VYvfl0dqeoLPb9Jpw1xoUXaVcGR8ExmYNm1w2vdGdJkEUYD/2pqg==} + dependencies: + picocolors: 1.0.0 + sisteransi: 1.0.5 + dev: false + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -727,6 +771,16 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true + /@types/yargs-parser@21.0.0: + resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + dev: true + + /@types/yargs@17.0.24: + resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} + dependencies: + '@types/yargs-parser': 21.0.0 + dev: true + /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.35.0)(typescript@4.9.5): resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -964,7 +1018,6 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -983,7 +1036,6 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -1280,7 +1332,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} @@ -1298,7 +1349,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -1306,7 +1356,6 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1500,7 +1549,6 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -1611,7 +1659,6 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -2268,7 +2315,6 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true /get-func-name@2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} @@ -2567,7 +2613,6 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} @@ -3181,7 +3226,6 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -3383,7 +3427,6 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: true /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} @@ -3555,7 +3598,6 @@ packages: /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -3625,7 +3667,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -3685,7 +3726,6 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} @@ -4131,7 +4171,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-text@1.0.9: resolution: {integrity: sha512-NWfjspSgMDXQIMpKM56AwCQPI01OMFRYYJBh6dGNCfH7AOl+j/VqqbiopgJ4VuQfSluqLc+2ekqaPNpYAGZ/Vg==} @@ -4167,7 +4206,6 @@ packages: /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -4187,7 +4225,6 @@ packages: /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: true /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} @@ -4217,7 +4254,6 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}