Browse Source

Implement CLI package

Add CLI package for consuming backend core API.
master
TheoryOfNekomata 11 months ago
parent
commit
1ce787f448
24 changed files with 626 additions and 52 deletions
  1. +9
    -0
      packages/cli/.eslintrc
  2. +107
    -0
      packages/cli/.gitignore
  3. +72
    -0
      packages/cli/package.json
  4. +3
    -0
      packages/cli/pridepack.json
  5. +5
    -0
      packages/cli/src/cli.ts
  6. +15
    -0
      packages/cli/src/commands.ts
  7. +9
    -0
      packages/cli/src/index.ts
  8. +42
    -0
      packages/cli/src/modules/adder/adder.controller.ts
  9. +21
    -0
      packages/cli/src/modules/adder/adder.service.ts
  10. +2
    -0
      packages/cli/src/modules/adder/index.ts
  11. +64
    -0
      packages/cli/test/index.test.ts
  12. +24
    -0
      packages/cli/tsconfig.eslint.json
  13. +24
    -0
      packages/cli/tsconfig.json
  14. +16
    -5
      packages/core/src/index.ts
  15. +9
    -1
      packages/core/test/index.test.ts
  16. +18
    -1
      packages/web-api/package.json
  17. +1
    -0
      packages/web-api/src/config.ts
  18. +1
    -3
      packages/web-api/src/index.ts
  19. +39
    -0
      packages/web-api/src/modules/adder/adder.controller.ts
  20. +21
    -0
      packages/web-api/src/modules/adder/adder.service.ts
  21. +2
    -0
      packages/web-api/src/modules/adder/index.ts
  22. +7
    -16
      packages/web-api/src/routes.ts
  23. +61
    -8
      packages/web-api/test/index.test.ts
  24. +54
    -18
      pnpm-lock.yaml

+ 9
- 0
packages/cli/.eslintrc View File

@@ -0,0 +1,9 @@
{
"root": true,
"extends": [
"lxsmnsyc/typescript"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
}
}

+ 107
- 0
packages/cli/.gitignore View File

@@ -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

+ 72
- 0
packages/cli/package.json View File

@@ -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 <allan.crisostomo@outlook.com>",
"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"
}
}

+ 3
- 0
packages/cli/pridepack.json View File

@@ -0,0 +1,3 @@
{
"target": "es2018"
}

+ 5
- 0
packages/cli/src/cli.ts View File

@@ -0,0 +1,5 @@
import yargs from 'yargs';

export const createCli = (argv: typeof process.argv) => {
return yargs(argv);
};

+ 15
- 0
packages/cli/src/commands.ts View File

@@ -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 <a> <b>',
describe: 'Add two numbers',
handler: adderController.addNumbers,
});

return cli;
};

+ 9
- 0
packages/cli/src/index.ts View File

@@ -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();

+ 42
- 0
packages/cli/src/modules/adder/adder.controller.ts View File

@@ -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<void>;
}

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);
}
}
}

+ 21
- 0
packages/cli/src/modules/adder/adder.service.ts View File

@@ -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,
};

+ 2
- 0
packages/cli/src/modules/adder/index.ts View File

@@ -0,0 +1,2 @@
export * from './adder.controller';
export * from './adder.service';

+ 64
- 0
packages/cli/test/index.test.ts View File

@@ -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<typeof process.exit>;
let exitReal: typeof process.exit;

beforeAll(() => {
exitReal = process.exit.bind(process);
const processMut = process as unknown as Record<string, unknown>;
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);
});
});

+ 24
- 0
packages/cli/tsconfig.eslint.json View File

@@ -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/*"],
}
}
}

+ 24
- 0
packages/cli/tsconfig.json View File

@@ -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/*"],
}
}
}

+ 16
- 5
packages/core/src/index.ts View File

@@ -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<string, unknown>;
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;


+ 9
- 1
packages/core/test/index.test.ts View File

@@ -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);
});
});

+ 18
- 1
packages/web-api/package.json View File

@@ -50,5 +50,22 @@
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"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": {
"*": {}
}
}

+ 1
- 0
packages/web-api/src/config.ts View File

@@ -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';


+ 1
- 3
packages/web-api/src/index.ts View File

@@ -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);


+ 39
- 0
packages/web-api/src/modules/adder/adder.controller.ts View File

@@ -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);
}
}
}

+ 21
- 0
packages/web-api/src/modules/adder/adder.service.ts View File

@@ -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,
};

+ 2
- 0
packages/web-api/src/modules/adder/index.ts View File

@@ -0,0 +1,2 @@
export * from './adder.controller';
export * from './adder.service';

+ 7
- 16
packages/web-api/src/routes.ts View File

@@ -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;


+ 61
- 8
packages/web-api/test/index.test.ts View File

@@ -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);
});
});

+ 54
- 18
pnpm-lock.yaml View File

@@ -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==}


Loading…
Cancel
Save