diff --git a/.github/actions/test-create-project/action.yml b/.github/actions/test-create-project/action.yml new file mode 100644 index 0000000..778d475 --- /dev/null +++ b/.github/actions/test-create-project/action.yml @@ -0,0 +1,74 @@ +name: 'Create project' +description: 'Runs create-node-project and performs tests' +inputs: + options: + description: 'create-node-app options' + required: true + dbConnection: + description: 'DB_CONNECTION_STRING env var' + default: 'postgresql://postgres:postgres@localhost:5432/postgres' +runs: + using: 'composite' + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: npm-${{ hashFiles('package-lock.json') }} + restore-keys: npm- + + - name: Install dependencies + run: npm ci --ignore-scripts + shell: bash + + - name: Build the project + run: npm run build + shell: bash + + - name: Run npm link + run: npm link + shell: bash + + - name: Create project + run: create-node-app ${{ inputs.options }} + shell: bash + + - name: Build created project + working-directory: ./node-app + run: npm run build + shell: bash + + - name: Run lint + working-directory: ./node-app + run: npm run ci-lint + shell: bash + + - name: Run tests + working-directory: ./node-app + run: npm run ci-test + shell: bash + env: + DB_CONNECTION_STRING: ${{inputs.dbConnection}} + + - name: Run start + if: ${{ !contains(inputs.options, '--api none') }} + working-directory: ./node-app + run: | + npm run start & + start_pid=$! + sleep 10 + kill $start_pid + shell: bash + env: + DB_CONNECTION_STRING: ${{inputs.dbConnection}} + + - name: Run start + if: ${{ contains(inputs.options, '--api none') }} + working-directory: ./node-app + shell: bash + run: npm run start + env: + DB_CONNECTION_STRING: ${{inputs.dbConnection}} diff --git a/.github/workflows/create-projects.yml b/.github/workflows/create-projects.yml index a089957..5f80fdc 100644 --- a/.github/workflows/create-projects.yml +++ b/.github/workflows/create-projects.yml @@ -17,48 +17,48 @@ jobs: strategy: fail-fast: false matrix: - create-app-command: ["create-node-app cloudrun", "create-node-app cloudrun-graphql"] + create-app-options: + - "--api rest --database none --pipeline cloudrun-gitlab" + - "--api graphql --database none --pipeline cloudrun-gitlab" + - "--api rest --database none --pipeline none" + - "--api none --database none --pipeline cloudrun-gitlab" runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Cache dependencies - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - id: create-node-app + uses: ./.github/actions/test-create-project with: - path: ~/.npm - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: npm- - - - name: Install dependencies - run: npm ci --ignore-scripts - - - name: Build the project - run: npm run build - - - name: Run npm link - run: npm link - - - name: Create project - run: ${{ matrix.create-app-command }} - - - name: Build created project - working-directory: ./node-app - run: npm run build + options: ${{ matrix.create-app-options }} - - name: Run lint - working-directory: ./node-app - run: npm run ci-lint + create-projects-with-postgres: + needs: "build" + services: + postgres: + image: postgres:17 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + POSTGRES_USER: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + strategy: + fail-fast: false + matrix: + create-app-options: + - "--api none --database postgres-knex --pipeline none" + - "--api rest --database postgres-knex --pipeline cloudrun-gitlab" + - "--api graphql --database postgres-knex --pipeline cloudrun-gitlab" + runs-on: ubuntu-latest - - name: Run tests - working-directory: ./node-app - run: npm run ci-test - - - name: Run start - working-directory: ./node-app - run: | - npm run start & - start_pid=$! - sleep 10 - kill $start_pid \ No newline at end of file + steps: + - uses: actions/checkout@v4 + - id: create-node-app + uses: ./.github/actions/test-create-project + with: + options: ${{ matrix.create-app-options }} \ No newline at end of file diff --git a/AUTHORS b/AUTHORS index 30f14d2..c2ebf77 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Jiri Smolik Patrik Hoffmann -Roman Filatov \ No newline at end of file +Roman Filatov +Pavel Švagr \ No newline at end of file diff --git a/README.md b/README.md index 71471f6..03adf36 100644 --- a/README.md +++ b/README.md @@ -6,34 +6,42 @@ # Create Node App -CLI to help you set up Node.js TypeScript project. Set up project includes +CLI to help you set up a Node.js TypeScript project. The setup includes: - code style tools (prettier, lint) -- testing (using jest) -- infrastructure files of your choice (Docker, etc.) -- GitLab CI and npm ci-\* scripts (for Ackee CI/CD pipelines) +- testing (using mocha) +- infrastructure files of your choice (PostgreSQL etc.) +- CI pipeline templates (based on Ackee GitLab CI/CD pipelines) ## Usage Run directly from GitHub repo via npx: ``` -Usage: npm exec --ignore-scripts -- github:AckeeCZ/create-node-app STARTER [OPTIONS] [DIRECTORY] - -STARTER Which template to setup (required) +Usage: npm exec --ignore-scripts -- github:AckeeCZ/create-node-app [OPTIONS] Options: - --dir, -d DIR Destination directory (default: ./node-app) - --project-name, -n NAME Google Cloud project name (default: directory basename) - --force, -f Overwrite existing destination directory if it's not empty - --help, -h Show this help message - -Starters available: - cloudrun Cloud Run + express - cloudrun-graphql Cloud Run + graphql + -d, --dir Destination directory [string] [default: "./node-app"] + -D, --debug Enables debug logs [boolean] [default: false] + -n, --project-name Google Cloud project name [string] [default: "node-app"] + -f, --force Overwrite existing destination if it's not empty + [boolean] [default: false] + --api Selects API + [string] [choices: "graphql", "rest"] + --database Selects database as database + [string] [choices: "postgres-knex"] + --pipeline Selects pipeline + [string] [choices: "cloudrun-gitlab"] + --version Show version number [boolean] + --help Show help [boolean] ``` -Supported starter templates: +## Setup options -- [Cloud Run](./starter/cloudrun/README.md) -- [GraphQL Cloud Run](./starter/cloudrun-graphql/README.md) +- API layer + - [RESTful](starter/api/rest/) + - [GraphQL](starter/api/graphql/) +- Database + - [PostgreSQL](starter/infra/postgresql-knex/) using [Knex](https://github.com/knex/knex) +- Pipelines + - [GitLab CloudRun](starter/pipeline/cloudrun-gitlab/) diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..e576c56 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,42 @@ +# Development 👷 + +## Starters + +Starters are folders containing files and structure that can be optionally added to the final created repository by `create-node-app` (cna). The base folder structure and tooling that should be available in every application created by cna is located in the [\_base](../starter/_base) folder. + +Each additional starter is an addition to this base. When a user selects a specific starter, all contents are copied into the final directory **except for specific files that require content merging**. Every file that is merged uses its own merger defined in the [Mergers](../src/Mergers/) directory. + +Each starter directory must contain a `node-app.jsonc` configuration file that defines the starter's metadata for the cna. + +### Grouping and sorting + +Starters are grouped into categories called "modules". These indicate that only one starter should be selected from each group. For example, under the API module there can be GraphQL and RESTful API starters, but the created application can have only one of those. + +The order for injection into the final repository is alphabetical based on the module fields. The logic for grouping and sorting is as follows: + +1. **Base Starter**: The `_base` starter is always built first +2. **Selected Starters**: Each selected starter is built in the order of user selection +3. **npm install**: Dependencies are installed +4. **Prebuild Scripts**: All `prebuild` scripts from selected starters are executed +5. **Final Build**: `npm run build` is executed + +### Configuration + +The `node-app.jsonc` file is a JSON with Comments file that configures how a starter behaves during the build process. The structure is as follows (fields with \* are required): + +- `id`\* (`string`): Unique identifier +- `name`\* (`string`): Displayed in the CLI in the form of ` ` e.g. `RESTful API` +- `module`\* (`string`): The category this starter belongs to (e.g., "API", "database") +- `prebuild` (`string[]`): Array of npm script names to run before the main build +- `replace` (`string[]`): Array of file paths (relative to project root) where string replacements should be applied + +#### Example RESTful API `node-app.jsonc` + +```jsonc +{ + "module": "API", + "id": "rest", + "name": "RESTful", + "prebuild": ["generate:api"], +} +``` diff --git a/lib/Bootstrap.js b/lib/Bootstrap.js deleted file mode 100644 index ab80336..0000000 --- a/lib/Bootstrap.js +++ /dev/null @@ -1,91 +0,0 @@ -import { CloudRunStarter } from './cloudrun/CloudRunStarter.js' -import { Npm } from './Npm.js' -import { Toolbelt } from './Toolbelt.js' -import * as path from 'path' -import { PackageJson } from './PackageJson.js' -import { GraphQLStarter } from './cloudrun-graphql/GraphQLStarter.js' -import yargs from 'yargs' -import { hideBin } from 'yargs/helpers' -import { logger } from './Logger.js' -export class Bootstrap { - constructor() { - this.starters = [new CloudRunStarter(), new GraphQLStarter()] - } - runCLI(args) { - const cli = yargs(hideBin(args)) - .usage('create-node-app [options]') - .positional('starter', { - name: 'starter', - type: 'string', - required: true, - description: 'Which template to setup (required)', - choices: this.starters.map(starter => starter.name), - }) - .option('dir', { - type: 'string', - alias: 'd', - default: './node-app', - description: 'Destination directory', - }) - .option('project-name', { - type: 'string', - alias: 'n', - default: 'node-app', - description: 'Google Cloud project name', - }) - .option('force', { - type: 'boolean', - alias: 'f', - default: false, - description: - "Overwrite existing destination directory if it's not empty", - }) - .version('1.0.0') - .help() - const parsedArgs = cli.parseSync() - const starterArg = parsedArgs._[0] - const starter = this.starters.find(x => x.name === starterArg) - const destination = path.normalize(parsedArgs.dir) - if (!starter) { - logger.info('Invalid starter') - cli.showHelp() - process.exit(1) - } - logger.info(`starter=${starter.name}, destination=${destination}`) - const npm = new Npm({ dir: destination }) - const packageJson = new PackageJson(npm) - const toolbelt = new Toolbelt({ - npm, - packageJson, - assetDirectory: path.join( - import.meta.dirname, - '..', - 'starter', - starter.name - ), - sharedDirectory: path.join( - import.meta.dirname, - '..', - 'starter', - 'shared' - ), - destination: destination, - projectName: parsedArgs.projectName, - }) - starter.setToolbelt(toolbelt) - if (!toolbelt.isDirectoryEmpty(destination)) { - if (!parsedArgs.force) { - logger.info( - `Directory '${destination}' already exists and is not empty. Use --force or -f flag to overwrite the existing directory.` - ) - process.exit(1) - } else { - logger.info(`Overwriting existing directory '${destination}'`) - } - } - toolbelt.mkdir(destination, { overwrite: parsedArgs.force }) - toolbelt.npm.init() - starter.install() - } -} -//# sourceMappingURL=Bootstrap.js.map diff --git a/lib/Bootstrap.js.map b/lib/Bootstrap.js.map deleted file mode 100644 index 1a35f02..0000000 --- a/lib/Bootstrap.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Bootstrap.js","sourceRoot":"","sources":["../src/Bootstrap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Logger.js b/lib/Logger.js deleted file mode 100644 index 904fa13..0000000 --- a/lib/Logger.js +++ /dev/null @@ -1,12 +0,0 @@ -export const logger = { - info: message => { - console.log(message) - }, - verbose: message => { - console.log(message) - }, - error: message => { - console.log(message) - }, -} -//# sourceMappingURL=Logger.js.map diff --git a/lib/Logger.js.map b/lib/Logger.js.map deleted file mode 100644 index 43a092d..0000000 --- a/lib/Logger.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Logger.js","sourceRoot":"","sources":["../src/Logger.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE;QACxB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtB,CAAC;IACD,OAAO,EAAE,CAAC,OAAe,EAAE,EAAE;QAC3B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtB,CAAC;IACD,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;QACzB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtB,CAAC;CACF,CAAA"} \ No newline at end of file diff --git a/lib/Npm.js b/lib/Npm.js deleted file mode 100644 index cb79e3b..0000000 --- a/lib/Npm.js +++ /dev/null @@ -1,35 +0,0 @@ -import * as childProcess from 'child_process' -import { logger } from './Logger.js' -export class Npm { - constructor(settings) { - this.dir = settings?.dir - } - run(args) { - logger.info(`> npm ${args.join(' ')}`) - const result = this.dir - ? childProcess.spawnSync('npm', args, { - cwd: this.dir, - }) - : childProcess.spawnSync('npm', args) - if ((result?.status ?? 0) > 0) { - logger.info( - `Failed npm command: npm ${args.join(' ')}. ${String(result.output)}` - ) - } - } - init() { - this.run(['init', '--yes']) - } - i(module) { - if (!module) { - return this.run(['i']) - } - const args = ['i', module] - this.run(args) - } - iDev(module) { - const args = ['i', '-D', module] - this.run(args) - } -} -//# sourceMappingURL=Npm.js.map diff --git a/lib/Npm.js.map b/lib/Npm.js.map deleted file mode 100644 index aecb5fe..0000000 --- a/lib/Npm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Npm.js","sourceRoot":"","sources":["../src/Npm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,MAAM,OAAO,GAAG;IAEd,YAAY,QAAyB;QACnC,IAAI,CAAC,GAAG,GAAG,QAAQ,EAAE,GAAW,CAAA;IAClC,CAAC;IACM,GAAG,CAAC,IAAc;QACvB,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG;YACrB,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;gBAClC,GAAG,EAAE,IAAI,CAAC,GAAG;aACd,CAAC;YACJ,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CACT,2BAA2B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CACtE,CAAA;QACH,CAAC;IACH,CAAC;IACM,IAAI;QACT,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC7B,CAAC;IAEM,CAAC,CAAC,MAAe;QACtB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACxB,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC;IACM,IAAI,CAAC,MAAc;QACxB,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;QAChC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC;CACF"} \ No newline at end of file diff --git a/lib/PackageJson.js b/lib/PackageJson.js deleted file mode 100644 index 40779a6..0000000 --- a/lib/PackageJson.js +++ /dev/null @@ -1,43 +0,0 @@ -import * as path from 'path' -import * as fs from 'fs' -import * as lodash from 'lodash-es' -import { logger } from './Logger.js' -export class PackageJson { - constructor(npm) { - let packagejsonPath = './package.json' - if (npm.dir) { - packagejsonPath = path.normalize(`${npm.dir}/${packagejsonPath}`) - } - this.path = packagejsonPath - this.npm = npm - } - setType(type) { - this.mergeWith({ - type, - }) - } - toJSON() { - return JSON.parse(fs.readFileSync(this.path, 'utf-8')) - } - runScript(name) { - this.npm.run(['run', name]) - } - addNpmScript(name, command) { - this.mergeWith({ - scripts: { - [name]: command, - }, - }) - } - // Updated package json using merge with given object - mergeWith(partialWith) { - const json = lodash.merge(this.toJSON(), partialWith) - logger.info(`> package.json updated ${JSON.stringify(partialWith)}`) - fs.writeFileSync( - path.join(this.path), - JSON.stringify(json, null, 2), - 'utf-8' - ) - } -} -//# sourceMappingURL=PackageJson.js.map diff --git a/lib/PackageJson.js.map b/lib/PackageJson.js.map deleted file mode 100644 index 01d3424..0000000 --- a/lib/PackageJson.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"PackageJson.js","sourceRoot":"","sources":["../src/PackageJson.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,MAAM,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,MAAM,OAAO,WAAW;IAGtB,YAAY,GAAQ;QAClB,IAAI,eAAe,GAAG,gBAAwB,CAAA;QAC9C,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,eAAe,EAAE,CAAS,CAAA;QAC3E,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;QAC3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;IAChB,CAAC;IACM,OAAO,CAAC,IAA2B;QACxC,IAAI,CAAC,SAAS,CAAC;YACb,IAAI;SACL,CAAC,CAAA;IACJ,CAAC;IACM,MAAM;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IACxD,CAAC;IACM,SAAS,CAAC,IAAY;QAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;IAC7B,CAAC;IACM,YAAY,CAAC,IAAY,EAAE,OAAe;QAC/C,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE;gBACP,CAAC,IAAI,CAAC,EAAE,OAAO;aAChB;SACF,CAAC,CAAA;IACJ,CAAC;IACD,qDAAqD;IAC9C,SAAS,CAAC,WAAgB;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAA;QACrD,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QACpE,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EACpB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAC7B,OAAO,CACR,CAAA;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/lib/Starter.js b/lib/Starter.js deleted file mode 100644 index 26460e8..0000000 --- a/lib/Starter.js +++ /dev/null @@ -1,2 +0,0 @@ -export {} -//# sourceMappingURL=Starter.js.map diff --git a/lib/Starter.js.map b/lib/Starter.js.map deleted file mode 100644 index 7a9fc2e..0000000 --- a/lib/Starter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Starter.js","sourceRoot":"","sources":["../src/Starter.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/lib/Toolbelt.js b/lib/Toolbelt.js deleted file mode 100644 index 9a1c313..0000000 --- a/lib/Toolbelt.js +++ /dev/null @@ -1,100 +0,0 @@ -import * as path from 'path' -import * as fs from 'fs' -import { logger } from './Logger.js' -export class Toolbelt { - constructor(params) { - this.npm = params.npm - this.packageJson = params.packageJson - this.assetDirectory = params.assetDirectory - this.sharedDirectory = params.sharedDirectory - this.destination = params.destination - this.projectName = params.projectName - } - stringToPath(str) { - return path.normalize(str) - } - isDirectoryEmpty(dirpath) { - const path = this.stringToPath(dirpath) - if (!fs.existsSync(path)) { - return true - } - const stat = fs.statSync(path) - if (!stat.isDirectory()) { - return true - } - const contents = fs.readdirSync(path) - return contents.length === 0 - } - mkdir(dirpath, option) { - dirpath = this.stringToPath(dirpath) - const rootPath = ['.', './'] - if (!rootPath.includes(dirpath)) { - if (fs.existsSync(dirpath) && option?.overwrite) { - fs.rmSync(dirpath, { recursive: true }) - } - fs.mkdirSync(dirpath, { recursive: true }) - } - } - /** - * Like cp, but second argument does not need to include file name - * the name is preserved. - */ - cpFile(a, b, option) { - a = this.stringToPath(a) - b = this.stringToPath(b) - const file = path.basename(a) - this.cp(a, this.stringToPath(`${b}/${option?.destFileName ?? file}`)) - } - cp(a, b) { - a = this.stringToPath(a) - b = this.stringToPath(b) - logger.info(`> cp ${a} ${b}`) - fs.copyFileSync(a, b) - } - copyAsset(name, destination) { - let destinationName = name - if (path.basename(name) === '.gitignore') { - name = '.gitignore_' - destinationName = '.gitignore' - } - name = this.stringToPath(name) - destination = this.stringToPath(this.destination) - this.cpFile(`${this.assetDirectory}/${name}`, destination, { - destFileName: destinationName, - }) - } - copySharedAsset(name, destination) { - let destinationName = name - if (path.basename(name) === '.gitignore') { - name = '.gitignore_' - destinationName = '.gitignore' - } - name = this.stringToPath(name) - destination = this.stringToPath(this.destination) - this.cpFile(`${this.sharedDirectory}/${name}`, destination, { - destFileName: destinationName, - }) - } - replaceInFile(filePath, placeholder, replacement = 'REPLACEME') { - filePath = this.stringToPath(`${this.destination}/${filePath}`) - let content = fs.readFileSync(filePath, 'utf8') - /* eslint-disable-next-line security/detect-non-literal-regexp */ - content = content.replace(new RegExp(placeholder, 'g'), replacement) - fs.writeFileSync(filePath, content) - } - symlink(linkName, linkedFile) { - linkName = this.stringToPath(linkName) - linkedFile = this.stringToPath(linkedFile) - logger.info(`> ln -s ${linkName} ${linkedFile}`) - try { - fs.symlinkSync(linkedFile, linkName) - } catch (error) { - if ('code' in error && error.code === 'EEXIST') { - // OK - } else { - throw error - } - } - } -} -//# sourceMappingURL=Toolbelt.js.map diff --git a/lib/Toolbelt.js.map b/lib/Toolbelt.js.map deleted file mode 100644 index bd30212..0000000 --- a/lib/Toolbelt.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Toolbelt.js","sourceRoot":"","sources":["../src/Toolbelt.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/cloudrun-graphql/GraphQLStarter.js b/lib/cloudrun-graphql/GraphQLStarter.js deleted file mode 100644 index 166840e..0000000 --- a/lib/cloudrun-graphql/GraphQLStarter.js +++ /dev/null @@ -1,168 +0,0 @@ -export class GraphQLStarter { - constructor() { - this.name = 'cloudrun-graphql' - } - setToolbelt(toolbelt) { - this.toolbelt = toolbelt - return this - } - install() { - if (this.toolbelt == null) { - throw new Error('No toolbelt') - } - const tb = this.toolbelt - tb.copySharedAsset('.gitignore') - tb.copySharedAsset('.gitlab-ci.yml') - tb.copySharedAsset('.nvmrc') - tb.copySharedAsset('Dockerfile') - tb.copySharedAsset('.dockerignore') - tb.mkdir(tb.stringToPath(`${tb.destination}/ci-branch-config`)) - tb.copySharedAsset('ci-branch-config/common.env') - tb.replaceInFile( - `ci-branch-config/common.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/development.env') - tb.replaceInFile( - `ci-branch-config/development.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/stage.env') - tb.replaceInFile( - `ci-branch-config/stage.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/master.env') - tb.replaceInFile( - `ci-branch-config/master.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/docker-compose`)) - tb.copySharedAsset('docker-compose/docker-compose-entrypoint.sh') - tb.copySharedAsset('docker-compose/docker-compose.ci.yml') - tb.copySharedAsset('docker-compose/docker-compose.local.yml') - tb.copySharedAsset('docker-compose/docker-compose.override.yml') - tb.symlink( - `${tb.destination}/docker-compose/docker-compose.override.yml`, - `${tb.destination}/docker-compose/docker-compose.local.yml` - ) - tb.copySharedAsset('docker-compose/docker-compose.yml') - tb.replaceInFile( - `docker-compose/docker-compose.yml`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.npm.iDev('typescript') - tb.npm.iDev('@types/node') - tb.npm.iDev('ts-node') - tb.npm.i('source-map-support') - tb.copySharedAsset('tsconfig.json') - tb.packageJson.addNpmScript( - 'build:graphql-types', - 'graphql-codegen --config codegen.yml' - ) - tb.packageJson.addNpmScript( - 'build:copy-schema', - 'mkdir -p ./dist/view/graphql/schema && cp -r ./src/view/graphql/schema ./dist/view/graphql/schema' - ) - tb.packageJson.addNpmScript( - 'build', - 'npm run build:graphql-types && npm run build:copy-schema && tsc' - ) - tb.packageJson.addNpmScript( - 'start', - 'node -r source-map-support/register dist/index.js' - ) - tb.npm.i('configuru') - tb.npm.i('pino') - tb.npm.iDev('pino-pretty') - tb.copyAsset('.env.jsonc') - tb.mkdir(tb.stringToPath(`${tb.destination}/src`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/errors`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/ports`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/utils`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/domain/errors/codes.ts') - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/ports/logger.d.ts') - tb.copyAsset('src/adapters/pino.logger.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql/resolvers`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql/schema`)) - tb.copyAsset('src/config.ts') - tb.copyAsset('src/index.ts') - tb.copyAsset('src/container.ts') - tb.copyAsset('src/context.ts') - tb.copyAsset('codegen.yml') - tb.copyAsset('src/view/controller.ts') - tb.copyAsset('src/view/server.ts') - tb.copyAsset('src/view/graphql/schema.ts') - tb.copyAsset('src/view/graphql/resolvers.ts') - tb.copyAsset('src/view/graphql/resolvers/greeting.resolver.ts') - tb.copyAsset('src/view/graphql/schema/schema.graphql') - tb.npm.iDev('mocha') - tb.npm.iDev('mocha-junit-reporter') - tb.npm.iDev('mocha-multi-reporters') - tb.npm.iDev('nyc') - tb.npm.iDev('tsx') - tb.npm.iDev('@types/mocha') - tb.npm.iDev('@istanbuljs/nyc-config-typescript') - tb.copySharedAsset('.mocharc.json', tb.destination) - tb.copySharedAsset('.mocha-junit-config.json', tb.destination) - tb.packageJson.setType('module') - tb.packageJson.addNpmScript('test', 'mocha') - tb.packageJson.addNpmScript( - 'ci-test:no-coverage', - 'npm run test -- --parallel=false -R mocha-multi-reporters --reporter-options configFile=.mocha-junit-config.json' - ) - tb.packageJson.addNpmScript( - 'ci-test', - 'nyc -a -r cobertura --report-dir output npm run ci-test:no-coverage' - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test`)) - tb.copySharedAsset('src/test/setup.ts') - tb.copyAsset('src/test/helloWorld.test.ts') - tb.npm.i('@as-integrations/express5') - tb.npm.iDev('@ackee/styleguide-backend-config') - tb.npm.iDev('prettier') - tb.npm.iDev('eslint') - tb.npm.iDev('eslint-formatter-gitlab@^5.0.0') - tb.copyAsset('.eslint.tsconfig.json') - tb.copyAsset('.eslintrc.cjs') - tb.copySharedAsset('prettier.config.cjs') - tb.packageJson.addNpmScript( - 'prettier', - "prettier --check --write '**/*.{ts,js,json,md}'" - ) - tb.packageJson.addNpmScript( - 'lint', - 'eslint --ext .ts --ext .graphql src -f codeframe --fix' - ) - tb.packageJson.addNpmScript('codestyle', 'npm run prettier && npm run lint') - tb.packageJson.addNpmScript( - 'ci-lint', - 'npm run lint -- -f checkstyle -o ./output/checkstyle-result.xml' - ) - tb.npm.i('@apollo/server') - tb.npm.iDev('@graphql-codegen/cli') - tb.npm.iDev('lodash') - tb.npm.iDev('@graphql-eslint/eslint-plugin') - tb.npm.iDev('@graphql-codegen/typescript') - tb.npm.iDev('@graphql-codegen/typescript-resolvers') - tb.npm.i('@graphql-tools/load-files') - tb.npm.i('@graphql-tools/merge') - tb.npm.i('@graphql-tools/schema') - tb.npm.i('graphql') - tb.npm.i('express') - tb.npm.iDev('@types/express') - tb.packageJson.runScript('build') - } -} -//# sourceMappingURL=GraphQLStarter.js.map diff --git a/lib/cloudrun-graphql/GraphQLStarter.js.map b/lib/cloudrun-graphql/GraphQLStarter.js.map deleted file mode 100644 index e887577..0000000 --- a/lib/cloudrun-graphql/GraphQLStarter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"GraphQLStarter.js","sourceRoot":"","sources":["../../src/cloudrun-graphql/GraphQLStarter.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/cloudrun/CloudRunStarter.js b/lib/cloudrun/CloudRunStarter.js deleted file mode 100644 index 73480cc..0000000 --- a/lib/cloudrun/CloudRunStarter.js +++ /dev/null @@ -1,167 +0,0 @@ -export class CloudRunStarter { - constructor() { - this.name = 'cloudrun' - } - setToolbelt(toolbelt) { - this.toolbelt = toolbelt - return this - } - install() { - if (this.toolbelt == null) { - throw new Error('No toolbelt') - } - const tb = this.toolbelt - tb.copySharedAsset('.gitignore') - tb.copySharedAsset('.gitlab-ci.yml') - tb.copySharedAsset('.nvmrc') - tb.copySharedAsset('Dockerfile') - tb.copySharedAsset('.dockerignore') - tb.mkdir(tb.stringToPath(`${tb.destination}/ci-branch-config`)) - tb.copySharedAsset('ci-branch-config/common.env') - tb.replaceInFile( - `ci-branch-config/common.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/development.env') - tb.replaceInFile( - `ci-branch-config/development.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/stage.env') - tb.replaceInFile( - `ci-branch-config/stage.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/master.env') - tb.replaceInFile( - `ci-branch-config/master.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/docker-compose`)) - tb.copySharedAsset('docker-compose/docker-compose-entrypoint.sh') - tb.copySharedAsset('docker-compose/docker-compose.ci.yml') - tb.copySharedAsset('docker-compose/docker-compose.local.yml') - tb.symlink( - `${tb.destination}/docker-compose/docker-compose.override.yml`, - `${tb.destination}/docker-compose/docker-compose.local.yml` - ) - tb.copySharedAsset('docker-compose/docker-compose.yml') - tb.replaceInFile( - `docker-compose/docker-compose.yml`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.npm.iDev('typescript') - tb.npm.iDev('@types/node') - tb.npm.iDev('ts-node') - tb.npm.i('source-map-support') - tb.copySharedAsset('tsconfig.json') - tb.packageJson.setType('module') - tb.packageJson.addNpmScript('build', 'tsc') - tb.packageJson.addNpmScript( - 'start', - 'node -r source-map-support/register dist/index.js' - ) - tb.npm.i('configuru') - tb.npm.i('pino') - tb.npm.i('pino-http') - tb.npm.iDev('pino-pretty') - tb.copyAsset('.env.jsonc') - tb.mkdir(tb.stringToPath(`${tb.destination}/src`)) - tb.copyAsset('src/config.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/container.ts') - tb.copyAsset('src/context.ts') - tb.copyAsset('src/index.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view`)) - tb.copyAsset(`/src/view/server.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest`)) - tb.copyAsset(`/src/view/rest/request.d.ts`) - tb.copyAsset(`/src/view/rest/routes.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/controller`)) - tb.copyAsset(`/src/view/rest/controller/health-check.controller.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/middleware`)) - tb.copyAsset(`/src/view/rest/middleware/context-middleware.ts`) - tb.copyAsset(`/src/view/rest/middleware/error-handler.ts`) - tb.copyAsset(`/src/view/rest/middleware/request-logger.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/util`)) - tb.copyAsset(`/src/view/rest/util/openapi.util.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/spec`)) - tb.copyAsset(`/src/view/rest/spec/openapi.yml`) - tb.npm.i('node-healthz') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain`)) - tb.copyAsset('src/domain/health-check.service.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/errors`)) - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/errors/codes.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/util`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/ports`)) - tb.copyAsset('src/domain/ports/logger.d.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/adapters/pino.logger.ts') - tb.npm.i('express') - tb.npm.iDev('@types/express') - tb.npm.iDev('mocha') - tb.npm.iDev('mocha-junit-reporter') - tb.npm.iDev('mocha-multi-reporters') - tb.npm.iDev('nyc') - tb.npm.iDev('@types/mocha') - tb.npm.iDev('@istanbuljs/nyc-config-typescript') - tb.npm.iDev('supertest') - tb.npm.iDev('@types/supertest') - tb.copySharedAsset('.mocharc.json', tb.destination) - tb.copySharedAsset('.mocha-junit-config.json', tb.destination) - tb.packageJson.addNpmScript('test', 'mocha') - tb.packageJson.addNpmScript( - 'ci-test:no-coverage', - 'npm run test -- --parallel=false -R mocha-multi-reporters --reporter-options configFile=.mocha-junit-config.json' - ) - tb.packageJson.addNpmScript( - 'ci-test', - 'nyc -a -r cobertura --report-dir output npm run ci-test:no-coverage' - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test`)) - tb.copySharedAsset('src/test/setup.ts') - tb.copyAsset('src/test/health-check.test.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test/util`)) - tb.copyAsset('src/test/util/openapi-test.util.ts') - tb.npm.iDev('@ackee/styleguide-backend-config') - tb.npm.iDev('prettier') - tb.npm.iDev('eslint') - tb.npm.iDev('eslint-formatter-gitlab@^5.0.0') - tb.copyAsset('.eslint.tsconfig.json') - tb.copyAsset('.eslintrc.cjs') - tb.copySharedAsset('prettier.config.cjs') - tb.packageJson.addNpmScript( - 'prettier', - "prettier --check --write '**/*.{ts,js,json,md}'" - ) - tb.packageJson.addNpmScript('lint', "eslint '**/*.ts' -f codeframe --fix") - tb.packageJson.addNpmScript('codestyle', 'npm run prettier && npm run lint') - tb.packageJson.addNpmScript( - 'ci-lint', - 'npm run lint -- -f checkstyle -o ./output/checkstyle-result.xml' - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/cli`)) - tb.copyAsset('src/view/cli/cli.ts') - tb.copyAsset('src/view/cli/README.md') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/cli/openapi`)) - tb.copyAsset('src/view/cli/openapi/generate.ts') - tb.npm.iDev('yargs') - tb.npm.iDev('yaml') - tb.packageJson.addNpmScript('cli', 'tsx ./src/view/cli/cli.ts') - tb.npm.iDev('openapi-typescript') - tb.npm.iDev('tsx') - tb.packageJson.addNpmScript( - 'generate:api', - 'npm run cli openapi generate src/view/rest/spec/openapi.yml && npm run codestyle' - ) - tb.packageJson.runScript('generate:api') - tb.packageJson.runScript('build') - } -} -//# sourceMappingURL=CloudRunStarter.js.map diff --git a/lib/cloudrun/CloudRunStarter.js.map b/lib/cloudrun/CloudRunStarter.js.map deleted file mode 100644 index fb99caf..0000000 --- a/lib/cloudrun/CloudRunStarter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"CloudRunStarter.js","sourceRoot":"","sources":["../../src/cloudrun/CloudRunStarter.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/types.js b/lib/types.js deleted file mode 100644 index 4ef431e..0000000 --- a/lib/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {} -//# sourceMappingURL=types.js.map diff --git a/lib/types.js.map b/lib/types.js.map deleted file mode 100644 index c768b79..0000000 --- a/lib/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f591b33..f40b378 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,10 @@ "version": "1.0.1", "license": "MIT", "dependencies": { + "fast-glob": "^3.3.3", + "inquirer": "^12.9.0", "lodash-es": "^4.17.21", + "ora": "^8.2.0", "source-map-support": "^0.5.21", "yargs": "^18.0.0" }, @@ -17,11 +20,11 @@ "create-node-app": "bin/create-node-app.js" }, "devDependencies": { - "@ackee/styleguide-backend-config": "^1.0.0", + "@ackee/styleguide-backend-config": "^1.0.1", "@types/lodash-es": "^4.17.12", "@types/node": "^20.19.0", "@types/yargs": "^17.0.33", - "prettier": "^2.8.1", + "prettier": "^3.0.0", "typescript": "^5.4.5" }, "engines": { @@ -29,15 +32,14 @@ } }, "node_modules/@ackee/styleguide-backend-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@ackee/styleguide-backend-config/-/styleguide-backend-config-1.0.0.tgz", - "integrity": "sha512-zVfzNsNL68cwOKQWA6+Yzj3O1gYCw/CTLj1x9u3MK++Yu7VHp52AsuEAWh8FAHMFbXntKENJlBjlwFwq463qJQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@ackee/styleguide-backend-config/-/styleguide-backend-config-1.0.1.tgz", + "integrity": "sha512-ntCyV2E3g7673wY4p0QoygLwKVyh+8MdOtGd/PFXsQSo0RV+jTa+2pRA2wi/QovTN68MF6ogIMWK6kiUQQlCnA==", "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "^8.16.0", "@typescript-eslint/parser": "^8.16.0", - "cspell-lib": "^6.17.0", "eslint": "^8.57.0", "eslint-config-love": "^84.1.1", "eslint-formatter-codeframe": "^7.32.1", @@ -52,22 +54,6 @@ "node": ">=18.0.0" } }, - "node_modules/@ackee/styleguide-backend-config/node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -2112,368 +2098,6 @@ "node": ">=6.9.0" } }, - "node_modules/@cspell/cspell-bundled-dicts": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.18.1.tgz", - "integrity": "sha512-3rGSZ5brzt9KFCoa1QVna8SiYnYzB8hqQyrWjtoJhV5SWjD4MpBtNt2xm5JtfNONWHeiHvkpPHasXjJvYXwDNg==", - "dev": true, - "dependencies": { - "@cspell/dict-ada": "^4.0.1", - "@cspell/dict-aws": "^3.0.0", - "@cspell/dict-bash": "^4.1.1", - "@cspell/dict-companies": "^3.0.5", - "@cspell/dict-cpp": "^4.0.1", - "@cspell/dict-cryptocurrencies": "^3.0.1", - "@cspell/dict-csharp": "^4.0.2", - "@cspell/dict-css": "^4.0.1", - "@cspell/dict-dart": "^2.0.1", - "@cspell/dict-django": "^4.0.1", - "@cspell/dict-docker": "^1.1.4", - "@cspell/dict-dotnet": "^4.0.1", - "@cspell/dict-elixir": "^4.0.1", - "@cspell/dict-en_us": "^4.1.2", - "@cspell/dict-en-gb": "1.1.33", - "@cspell/dict-filetypes": "^3.0.0", - "@cspell/dict-fonts": "^3.0.0", - "@cspell/dict-fullstack": "^3.0.0", - "@cspell/dict-gaming-terms": "^1.0.3", - "@cspell/dict-git": "^2.0.0", - "@cspell/dict-golang": "^5.0.1", - "@cspell/dict-haskell": "^4.0.1", - "@cspell/dict-html": "^4.0.2", - "@cspell/dict-html-symbol-entities": "^4.0.0", - "@cspell/dict-java": "^5.0.3", - "@cspell/dict-k8s": "^1.0.0", - "@cspell/dict-latex": "^3.1.0", - "@cspell/dict-lorem-ipsum": "^3.0.0", - "@cspell/dict-lua": "^3.0.0", - "@cspell/dict-node": "^4.0.2", - "@cspell/dict-npm": "^5.0.2", - "@cspell/dict-php": "^3.0.4", - "@cspell/dict-powershell": "^3.0.0", - "@cspell/dict-public-licenses": "^2.0.1", - "@cspell/dict-python": "^4.0.1", - "@cspell/dict-r": "^2.0.1", - "@cspell/dict-ruby": "^3.0.0", - "@cspell/dict-rust": "^3.0.0", - "@cspell/dict-scala": "^3.0.0", - "@cspell/dict-software-terms": "^3.0.7", - "@cspell/dict-sql": "^2.0.1", - "@cspell/dict-svelte": "^1.0.1", - "@cspell/dict-swift": "^2.0.1", - "@cspell/dict-typescript": "^3.1.0", - "@cspell/dict-vue": "^3.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@cspell/cspell-pipe": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.18.1.tgz", - "integrity": "sha512-IFtZBae5BCBIPZuRhEs0U0emFrh5hmN0N4+WR5paP4UurV5Ql9n2JsSj1Bmdx79aSFAw4mGpJnhZZtGQcFDnPQ==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@cspell/cspell-service-bus": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.18.1.tgz", - "integrity": "sha512-QVbVA8Ube+Z4ghywzsTQLxqdiCubYi7L/+KeFRatzh3bZ5K5pVcYHEbDhAlFdUj6FhXw0EP2n/Xb+8ZLye4LLg==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@cspell/cspell-types": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.18.1.tgz", - "integrity": "sha512-5X+ABUMPrCoCjQvbqb/HeCoNiSgUrJhR9O4tSlMU5/z0NRNLFSyjf+3LE6ZU2+kdwNU7tmYCr+cbCpb3UKpvQQ==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@cspell/dict-ada": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.0.1.tgz", - "integrity": "sha512-/E9o3nHrXOhYmQE43deKbxZcR3MIJAsa+66IzP9TXGHheKEx8b9dVMVVqydDDH8oom1H0U20NRPtu6KRVbT9xw==", - "dev": true - }, - "node_modules/@cspell/dict-aws": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-3.0.0.tgz", - "integrity": "sha512-O1W6nd5y3Z00AMXQMzfiYrIJ1sTd9fB1oLr+xf/UD7b3xeHeMeYE2OtcWbt9uyeHim4tk+vkSTcmYEBKJgS5bQ==", - "dev": true - }, - "node_modules/@cspell/dict-bash": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.1.tgz", - "integrity": "sha512-8czAa/Mh96wu2xr0RXQEGMTBUGkTvYn/Pb0o+gqOO1YW+poXGQc3gx0YPqILDryP/KCERrNvkWUJz3iGbvwC2A==", - "dev": true - }, - "node_modules/@cspell/dict-companies": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.0.5.tgz", - "integrity": "sha512-f5lVcL/dG2kUHh8QFLakU722lgMwqXSjZUdmW6QdOMmqcE8cgl+oN9qk/qYlCSBMsYA7uexwn3hIr4h0naoPlw==", - "dev": true - }, - "node_modules/@cspell/dict-cpp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-4.0.1.tgz", - "integrity": "sha512-mD6mn0XFCqHCz2j6p/7OQm3yNFn1dlQq6vip1pLynvNWDRz5yKYDVRUQCTEORT7ThS0dLpI4BjCX84YUKNhibA==", - "dev": true - }, - "node_modules/@cspell/dict-cryptocurrencies": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz", - "integrity": "sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w==", - "dev": true - }, - "node_modules/@cspell/dict-csharp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz", - "integrity": "sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==", - "dev": true - }, - "node_modules/@cspell/dict-css": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.1.tgz", - "integrity": "sha512-jxsncdeiN/wkZGqU8iLtn24n3e0Fwugj6T48rjWUItn/i3C9j2W7RXOVqd7ZIeWeV8ibyq0WWiwA8Ajg6XaKpA==", - "dev": true - }, - "node_modules/@cspell/dict-dart": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.0.1.tgz", - "integrity": "sha512-YRuDX9k2qPSWDEsM26j8o7KMvaZ0DXc74ijK/VRwaksm1CBRPBW289pe2TE2K7y4SJjTKXgQ9urOVlozeQDpuA==", - "dev": true - }, - "node_modules/@cspell/dict-django": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.0.1.tgz", - "integrity": "sha512-q3l7OH39qzeN2Y64jpY39SEAqki5BUzPTypnhzM40yT+LOGSWqSh9Ix5UecejtXPDVrD8vML+m7Bp5070h52HQ==", - "dev": true - }, - "node_modules/@cspell/dict-docker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.5.tgz", - "integrity": "sha512-SNEohOScQ+0+y9dp/jKTx60OOJQrf5es5BJ32gh5Ck3jKXNo4wd9KLgPOmQMUpencb5SGjrBsC4rr1fyfCwytg==", - "dev": true - }, - "node_modules/@cspell/dict-dotnet": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-4.0.1.tgz", - "integrity": "sha512-l11TqlUX8cDgsE/1Zrea1PqLn63s20MY3jKWMbQVB5DMDPDO2f8Pukckkwxq5p/cxDABEjuGzfF1kTX3pAakBw==", - "dev": true - }, - "node_modules/@cspell/dict-elixir": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.1.tgz", - "integrity": "sha512-IejBqiTTWSXpvBm6yg4qUfnJR0LwbUUCJcK5wXOMKEJitu3yDfrT9GPc6NQJXgokbg9nBjEyxVIzNcLgx2x3/Q==", - "dev": true - }, - "node_modules/@cspell/dict-en_us": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.1.4.tgz", - "integrity": "sha512-smRT8Rx38+z1kiNl3kBvadoPdYgxCovxw2rsuO4/XtLRlSEcGPQgYJ0CCdcXMd9bhMY5roXPCcvYkBsyUVvg4A==", - "dev": true - }, - "node_modules/@cspell/dict-en-gb": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", - "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", - "dev": true - }, - "node_modules/@cspell/dict-filetypes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.0.tgz", - "integrity": "sha512-Fiyp0z5uWaK0d2TfR9GMUGDKmUMAsOhGD5A0kHoqnNGswL2iw0KB0mFBONEquxU65fEnQv4R+jdM2d9oucujuA==", - "dev": true - }, - "node_modules/@cspell/dict-fonts": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-3.0.0.tgz", - "integrity": "sha512-zTZni0AbwBVG1MKA0WpwPyIJPVF+gp6neXDQzHcu4RUnuQ4uDu0PVEuZjGHCJWwwFoR5JmkqZxVSg1y3ufJODA==", - "dev": true - }, - "node_modules/@cspell/dict-fullstack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.0.1.tgz", - "integrity": "sha512-r077HcbxGQ0gSjs4eqryvb9cu8/Noe7pzl9QksxFIEaMgyP180DEaCLAOnat4KHl7X0wntipY+naY5PVRQUI9A==", - "dev": true - }, - "node_modules/@cspell/dict-gaming-terms": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.4.tgz", - "integrity": "sha512-hbDduNXlk4AOY0wFxcDMWBPpm34rpqJBeqaySeoUH70eKxpxm+dvjpoRLJgyu0TmymEICCQSl6lAHTHSDiWKZg==", - "dev": true - }, - "node_modules/@cspell/dict-git": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-2.0.0.tgz", - "integrity": "sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w==", - "dev": true - }, - "node_modules/@cspell/dict-golang": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-5.0.1.tgz", - "integrity": "sha512-djsJC7OVKUpFdRm/aqBJEUSGP3kw/MDhAt7udYegnyQt2WjL3ZnVoG7r5eOEhPEEKzWVBYoi6UKSNpdQEodlbg==", - "dev": true - }, - "node_modules/@cspell/dict-haskell": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.1.tgz", - "integrity": "sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ==", - "dev": true - }, - "node_modules/@cspell/dict-html": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.2.tgz", - "integrity": "sha512-BskOE2K3AtGLkcjdJmo+H6/fjdfDP4XYAsEGXpB26rvdnXAnGEstE/Q8Do6UfJCvgOVYCpdUZLcMIEpoTy7QhQ==", - "dev": true - }, - "node_modules/@cspell/dict-html-symbol-entities": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz", - "integrity": "sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==", - "dev": true - }, - "node_modules/@cspell/dict-java": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.4.tgz", - "integrity": "sha512-43VrLOLcBxavv6eyL4BpsnHrhVOgyYYeJqQRJG5XKObcpWy3+Lpadj58CfTVOr7M/Je3pUpd4tvsUhf/lWXMVA==", - "dev": true - }, - "node_modules/@cspell/dict-k8s": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.0.tgz", - "integrity": "sha512-XqIql+nd2DiuPuL+qPc24bN/L1mZY75kAYcuMBMW5iYgBoivkiVOg7br/aofX3ApajvHDln6tNkPZhmhsOg6Ww==", - "dev": true - }, - "node_modules/@cspell/dict-latex": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-3.1.0.tgz", - "integrity": "sha512-XD5S3FY0DrYiun2vm/KKOkeaD30LXp9v5EzVTVQvmxqQrQh0HvOT3TFD7lgKbyzZaG7E+l3wS94uwwm80cOmuw==", - "dev": true - }, - "node_modules/@cspell/dict-lorem-ipsum": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-3.0.0.tgz", - "integrity": "sha512-msEV24qEpzWZs2kcEicqYlhyBpR0amfDkJOs+iffC07si9ftqtQ+yP3lf1VFLpgqw3SQh1M1vtU7RD4sPrNlcQ==", - "dev": true - }, - "node_modules/@cspell/dict-lua": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-3.0.0.tgz", - "integrity": "sha512-WOhSCgS5wMxkGQJ8siB90iTB9ElquJB7FeqYSbJqqs6cUwH8G7MM/CEDPL6h7vCo0+v3GuxQ8yKWDSUcUhz9Lg==", - "dev": true - }, - "node_modules/@cspell/dict-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-4.0.2.tgz", - "integrity": "sha512-FEQJ4TnMcXEFslqBQkXa5HposMoCGsiBv2ux4IZuIXgadXeHKHUHk60iarWpjhzNzQLyN2GD7NoRMd12bK3Llw==", - "dev": true - }, - "node_modules/@cspell/dict-npm": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.3.tgz", - "integrity": "sha512-fEX67zIJISbS3gXVk/y/ZUvDIVtjc/CYJK7Mz0iTVrmlCKnLiD41lApe8v4g/12eE7hLfx/sfCXDrUWyzXVq1A==", - "dev": true - }, - "node_modules/@cspell/dict-php": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-3.0.4.tgz", - "integrity": "sha512-QX6zE/ZfnT3O5lSwV8EPVh8Va39ds34gSNNR8I4GWiuDpKcTkZPFi4OLoP3Tlhbl/3G0Ha35OkSDLvZfu8mnkA==", - "dev": true - }, - "node_modules/@cspell/dict-powershell": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-3.0.0.tgz", - "integrity": "sha512-pkztY9Ak4oc33q+Qxcn9/CTOKo4N8YIRRE6v67WwQOncA5QIJfcOPUrjfR3Z8SpzElXhu3s9qtWWSqbCy6qmcA==", - "dev": true - }, - "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.1.tgz", - "integrity": "sha512-NZNwzkL5BqKddepDxvX/Qbji378Mso1TdnV4RFAN8hJoo6dSR0fv2TTI/Y0i/YWBmfmQGyTpEztBXtAw4qgjiA==", - "dev": true - }, - "node_modules/@cspell/dict-python": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.0.1.tgz", - "integrity": "sha512-1wtUgyaTqRiQY0/fryk0oW22lcxNUnZ5DwteTzfatMdbgR0OHXTlHbI8vYxpHLWalSoch7EpLsnaymG+fOrt8g==", - "dev": true - }, - "node_modules/@cspell/dict-r": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.0.1.tgz", - "integrity": "sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==", - "dev": true - }, - "node_modules/@cspell/dict-ruby": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-3.0.0.tgz", - "integrity": "sha512-sA98T8Y1Pmq3RStVkO14E8vTWkq6JUn8c8PldiMyYgV0yfQgwhQfFAzlSfF3Gg2B0VkIdqt2et2SPN7f9wp7fQ==", - "dev": true - }, - "node_modules/@cspell/dict-rust": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-3.0.0.tgz", - "integrity": "sha512-L1T1IBsYJZVDmfOGAbVLcpc6arWxRRCSJYvHSwEDBGrNuMyJ4jx/NvBEz5crcKf4vVKgwVlXgzQlJJZ8AVxU9w==", - "dev": true - }, - "node_modules/@cspell/dict-scala": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-3.0.0.tgz", - "integrity": "sha512-sIiCQDIMMnNns/fzD61z5npbh5pypaKq07Orqe0+eRfdQpika8iRSGUGFHVbtdd1JzB1DyTCV2e8OwdaQiXqJQ==", - "dev": true - }, - "node_modules/@cspell/dict-software-terms": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.0.8.tgz", - "integrity": "sha512-otq0yIcG19rNXkmE/EGWgUK7ClLrn/BE4n5Di3HKLw6XEp0sNBp1DKf88bg0LvbWh15uCAJ5xKAzF1sVPy2Y3w==", - "dev": true - }, - "node_modules/@cspell/dict-sql": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.0.1.tgz", - "integrity": "sha512-7fvVcvy751cl31KMD5j04yMGq2UKj018/1hx3FNtdUI9UuUTMvhBrTAqHEEemR3ZeIC9i/5p5SQjwQ13bn04qw==", - "dev": true - }, - "node_modules/@cspell/dict-svelte": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.2.tgz", - "integrity": "sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q==", - "dev": true - }, - "node_modules/@cspell/dict-swift": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.1.tgz", - "integrity": "sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==", - "dev": true - }, - "node_modules/@cspell/dict-typescript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.0.tgz", - "integrity": "sha512-4hdLlQMOYrUbGfJg2cWnbsBUevObwgL76TLVC0rwnrkSwzOxAxiGaG39VtRMvgAAe2lX6L+jka3fy0MmxzFOHw==", - "dev": true - }, - "node_modules/@cspell/dict-vue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.0.tgz", - "integrity": "sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==", - "dev": true - }, - "node_modules/@cspell/strong-weak-map": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-6.18.1.tgz", - "integrity": "sha512-etyMLISiDzgFf1BSGpUBD62cHp9NrCyrOi+iT7WrJ+My0l6IPRIhANuAVp2JcsXxe28en4X3Bp/egd46Q5Rpkg==", - "dev": true, - "engines": { - "node": ">=14.6" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -2633,84 +2257,487 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, + "node_modules/@inquirer/checkbox": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", + "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, "engines": { - "node": ">=6.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, + "node_modules/@inquirer/confirm": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, + "node_modules/@inquirer/core": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", "license": "MIT", "dependencies": { - "eslint-scope": "5.1.1" + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=4.0" + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", + "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", + "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", + "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", + "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", + "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.0.tgz", + "integrity": "sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.2.0", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.15", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", + "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.0.tgz", + "integrity": "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", + "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2724,7 +2751,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2734,7 +2760,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2779,7 +2804,7 @@ "version": "20.19.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3080,15 +3105,41 @@ "uri-js": "^4.2.2" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3162,12 +3213,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -3424,7 +3469,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3588,22 +3632,48 @@ "node": ">=4" } }, - "node_modules/clear-module": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", - "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", - "dev": true, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", "dependencies": { - "parent-module": "^2.0.0", - "resolve-from": "^5.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -3657,22 +3727,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/comment-json": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", - "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", - "dev": true, - "dependencies": { - "array-timsort": "^1.0.3", - "core-util-is": "^1.0.3", - "esprima": "^4.0.1", - "has-own-prop": "^2.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3680,23 +3734,6 @@ "dev": true, "license": "MIT" }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3718,27 +3755,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", - "dev": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3754,120 +3770,6 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cspell-dictionary": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.18.1.tgz", - "integrity": "sha512-q+tK+MWvJs9xL8wv79YlGPddUFb3Usuqh+VB8D0Zs7Xlsa/cw9bljRluHkpQrNr8APdZijGlgQP8L0cEr0/rEw==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "cspell-trie-lib": "6.18.1", - "fast-equals": "^4.0.3", - "gensequence": "^4.0.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/cspell-glob": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.18.1.tgz", - "integrity": "sha512-6dBBtQ1lRnVPoM13GOv7mJflkIvEr93TN96saQPWoaQqX8jwmklcMmDUndIkLcA7TnyxBbi3Z3X+s68zj/YGqw==", - "dev": true, - "dependencies": { - "micromatch": "^4.0.5" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/cspell-grammar": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.18.1.tgz", - "integrity": "sha512-QPjOA9xwDPb3aoJXUOdL2aWX2wt8lPD7CoDROo8uruOXHAQzIY56q12EBy3jLIkxJFl9KAwtlEHkbLaJfTpIpg==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1" - }, - "bin": { - "cspell-grammar": "bin.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/cspell-io": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.18.1.tgz", - "integrity": "sha512-WIfiDdG/7235CbkrjKPYIkP9oT8VvWXVTAeq6JkJPH7bm2A/CoE8ClieVsbbJnPyJnetnCuOuuz/zmuheVD02g==", - "dev": true, - "dependencies": { - "@cspell/cspell-service-bus": "6.18.1", - "node-fetch": "^2.6.7" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/cspell-lib": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.18.1.tgz", - "integrity": "sha512-4MGjp51Ed8BbMPGXgqLGgUiWyb2DbOxgVEuWm8nxumxu7UmAWDBdMiD3QlY+ZYmfOJEVSa/kG7DTMrLQoeFwnQ==", - "dev": true, - "dependencies": { - "@cspell/cspell-bundled-dicts": "6.18.1", - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "@cspell/strong-weak-map": "6.18.1", - "clear-module": "^4.1.2", - "comment-json": "^4.2.3", - "configstore": "^5.0.1", - "cosmiconfig": "^8.0.0", - "cspell-dictionary": "6.18.1", - "cspell-glob": "6.18.1", - "cspell-grammar": "6.18.1", - "cspell-io": "6.18.1", - "cspell-trie-lib": "6.18.1", - "fast-equals": "^4.0.3", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "gensequence": "^4.0.3", - "import-fresh": "^3.3.0", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0", - "vscode-languageserver-textdocument": "^1.0.8", - "vscode-uri": "^3.0.7" - }, - "engines": { - "node": ">=14.6" - } - }, - "node_modules/cspell-trie-lib": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.18.1.tgz", - "integrity": "sha512-rV32bqchz0uYdK6uafaw5QnYImRWQMcT2RNbBo0LXN6XoYoTSgpnPWTxQauNLxOm1m+dfb3GdasoAsjgWkPGnQ==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "fs-extra": "^11.1.0", - "gensequence": "^4.0.3" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -4049,18 +3951,6 @@ "node": ">=6.0.0" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4102,15 +3992,6 @@ "node": ">=10.13.0" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -5773,19 +5654,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -5839,17 +5707,10 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-equals": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", - "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5866,7 +5727,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5893,7 +5753,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -5916,7 +5775,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5979,20 +5837,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -6048,15 +5892,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensequence": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.3.tgz", - "integrity": "sha512-izr+MKqJKjexkvLiPGhW96elQX8TuUR/su/xzILxjqzU1RDz1n1ZbqwDUnNFaRcq0gFR3oQfNH2JOH4Je1x/QA==", - "dev": true, - "engines": { - "node": ">=14" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -6215,18 +6050,6 @@ "node": "*" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", - "dev": true, - "dependencies": { - "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -6339,15 +6162,6 @@ "node": ">=4" } }, - "node_modules/has-own-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", - "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -6419,6 +6233,18 @@ "node": ">= 0.4" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -6494,11 +6320,31 @@ "dev": true, "license": "ISC" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "node_modules/inquirer": { + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.0.tgz", + "integrity": "sha512-LlFVmvWVCun7uEgPB3vups9NzBrjJn48kRNtFGw3xU1H5UXExTEz/oF1JGLaB0fvlkUB+W6JfgLcSEaSdH7RPA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/prompts": "^7.8.0", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^4.0.5", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, "node_modules/internal-slot": { "version": "1.1.0", @@ -6550,12 +6396,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", @@ -6677,7 +6517,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6699,6 +6538,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -6722,7 +6570,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6731,6 +6578,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -6761,7 +6620,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6784,15 +6642,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -6902,11 +6751,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/is-weakmap": { "version": "2.0.2", @@ -7024,12 +6879,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7057,18 +6906,6 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -7129,12 +6966,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7169,12 +7000,52 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/loose-envify": { "version": "1.4.0", @@ -7199,31 +7070,6 @@ "yallist": "^3.0.2" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -7238,7 +7084,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -7248,7 +7093,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -7258,6 +7102,18 @@ "node": ">=8.6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -7291,6 +7147,15 @@ "dev": true, "license": "MIT" }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7298,26 +7163,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -7475,6 +7320,21 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7493,6 +7353,68 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -7541,36 +7463,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", - "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", - "dev": true, - "dependencies": { - "callsites": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7627,7 +7519,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -7656,15 +7547,16 @@ } }, "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, + "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -7696,7 +7588,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -7871,15 +7762,6 @@ "node": ">=6" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -7901,42 +7783,48 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", "dependencies": { - "global-dirs": "^0.1.1" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -7960,11 +7848,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-async": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.5.tgz", + "integrity": "sha512-oN9GTgxUNDBumHTTDmQ8dep6VIJbgj9S3dPP+9XylVLIK4xB9XTXtKWROd5pnhdXR9k0EgO1JRcNh0T+Ny2FsA==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -7984,6 +7880,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -8048,6 +7953,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scslre": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", @@ -8224,12 +8135,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8257,6 +8162,18 @@ "source-map": "^0.6.0" } }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -8429,7 +8346,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -8507,7 +8423,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8516,12 +8431,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -8597,6 +8506,12 @@ "json5": "lib/cli.js" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -8701,15 +8616,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", @@ -8771,7 +8677,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -8818,27 +8724,6 @@ "node": ">=4" } }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -8880,18 +8765,6 @@ "punycode": "^2.1.0" } }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", - "dev": true - }, - "node_modules/vscode-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.7.tgz", - "integrity": "sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==", - "dev": true - }, "node_modules/vue-eslint-parser": { "version": "9.4.3", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", @@ -8917,22 +8790,6 @@ "eslint": ">=6.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9103,30 +8960,9 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", @@ -9178,18 +9014,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { "@ackee/styleguide-backend-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@ackee/styleguide-backend-config/-/styleguide-backend-config-1.0.0.tgz", - "integrity": "sha512-zVfzNsNL68cwOKQWA6+Yzj3O1gYCw/CTLj1x9u3MK++Yu7VHp52AsuEAWh8FAHMFbXntKENJlBjlwFwq463qJQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@ackee/styleguide-backend-config/-/styleguide-backend-config-1.0.1.tgz", + "integrity": "sha512-ntCyV2E3g7673wY4p0QoygLwKVyh+8MdOtGd/PFXsQSo0RV+jTa+2pRA2wi/QovTN68MF6ogIMWK6kiUQQlCnA==", "dev": true, "requires": { "@typescript-eslint/eslint-plugin": "^8.16.0", "@typescript-eslint/parser": "^8.16.0", - "cspell-lib": "^6.17.0", "eslint": "^8.57.0", "eslint-config-love": "^84.1.1", "eslint-formatter-codeframe": "^7.32.1", @@ -9199,14 +9046,6 @@ "eslint-plugin-security": "^3.0.1", "eslint-plugin-sonarjs": "^2.0.4", "prettier": "^3.4.2" - }, - "dependencies": { - "prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true - } } }, "@ampproject/remapping": { @@ -10526,353 +10365,6 @@ "@babel/helper-validator-identifier": "^7.27.1" } }, - "@cspell/cspell-bundled-dicts": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.18.1.tgz", - "integrity": "sha512-3rGSZ5brzt9KFCoa1QVna8SiYnYzB8hqQyrWjtoJhV5SWjD4MpBtNt2xm5JtfNONWHeiHvkpPHasXjJvYXwDNg==", - "dev": true, - "requires": { - "@cspell/dict-ada": "^4.0.1", - "@cspell/dict-aws": "^3.0.0", - "@cspell/dict-bash": "^4.1.1", - "@cspell/dict-companies": "^3.0.5", - "@cspell/dict-cpp": "^4.0.1", - "@cspell/dict-cryptocurrencies": "^3.0.1", - "@cspell/dict-csharp": "^4.0.2", - "@cspell/dict-css": "^4.0.1", - "@cspell/dict-dart": "^2.0.1", - "@cspell/dict-django": "^4.0.1", - "@cspell/dict-docker": "^1.1.4", - "@cspell/dict-dotnet": "^4.0.1", - "@cspell/dict-elixir": "^4.0.1", - "@cspell/dict-en_us": "^4.1.2", - "@cspell/dict-en-gb": "1.1.33", - "@cspell/dict-filetypes": "^3.0.0", - "@cspell/dict-fonts": "^3.0.0", - "@cspell/dict-fullstack": "^3.0.0", - "@cspell/dict-gaming-terms": "^1.0.3", - "@cspell/dict-git": "^2.0.0", - "@cspell/dict-golang": "^5.0.1", - "@cspell/dict-haskell": "^4.0.1", - "@cspell/dict-html": "^4.0.2", - "@cspell/dict-html-symbol-entities": "^4.0.0", - "@cspell/dict-java": "^5.0.3", - "@cspell/dict-k8s": "^1.0.0", - "@cspell/dict-latex": "^3.1.0", - "@cspell/dict-lorem-ipsum": "^3.0.0", - "@cspell/dict-lua": "^3.0.0", - "@cspell/dict-node": "^4.0.2", - "@cspell/dict-npm": "^5.0.2", - "@cspell/dict-php": "^3.0.4", - "@cspell/dict-powershell": "^3.0.0", - "@cspell/dict-public-licenses": "^2.0.1", - "@cspell/dict-python": "^4.0.1", - "@cspell/dict-r": "^2.0.1", - "@cspell/dict-ruby": "^3.0.0", - "@cspell/dict-rust": "^3.0.0", - "@cspell/dict-scala": "^3.0.0", - "@cspell/dict-software-terms": "^3.0.7", - "@cspell/dict-sql": "^2.0.1", - "@cspell/dict-svelte": "^1.0.1", - "@cspell/dict-swift": "^2.0.1", - "@cspell/dict-typescript": "^3.1.0", - "@cspell/dict-vue": "^3.0.0" - } - }, - "@cspell/cspell-pipe": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.18.1.tgz", - "integrity": "sha512-IFtZBae5BCBIPZuRhEs0U0emFrh5hmN0N4+WR5paP4UurV5Ql9n2JsSj1Bmdx79aSFAw4mGpJnhZZtGQcFDnPQ==", - "dev": true - }, - "@cspell/cspell-service-bus": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.18.1.tgz", - "integrity": "sha512-QVbVA8Ube+Z4ghywzsTQLxqdiCubYi7L/+KeFRatzh3bZ5K5pVcYHEbDhAlFdUj6FhXw0EP2n/Xb+8ZLye4LLg==", - "dev": true - }, - "@cspell/cspell-types": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.18.1.tgz", - "integrity": "sha512-5X+ABUMPrCoCjQvbqb/HeCoNiSgUrJhR9O4tSlMU5/z0NRNLFSyjf+3LE6ZU2+kdwNU7tmYCr+cbCpb3UKpvQQ==", - "dev": true - }, - "@cspell/dict-ada": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.0.1.tgz", - "integrity": "sha512-/E9o3nHrXOhYmQE43deKbxZcR3MIJAsa+66IzP9TXGHheKEx8b9dVMVVqydDDH8oom1H0U20NRPtu6KRVbT9xw==", - "dev": true - }, - "@cspell/dict-aws": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-3.0.0.tgz", - "integrity": "sha512-O1W6nd5y3Z00AMXQMzfiYrIJ1sTd9fB1oLr+xf/UD7b3xeHeMeYE2OtcWbt9uyeHim4tk+vkSTcmYEBKJgS5bQ==", - "dev": true - }, - "@cspell/dict-bash": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.1.tgz", - "integrity": "sha512-8czAa/Mh96wu2xr0RXQEGMTBUGkTvYn/Pb0o+gqOO1YW+poXGQc3gx0YPqILDryP/KCERrNvkWUJz3iGbvwC2A==", - "dev": true - }, - "@cspell/dict-companies": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.0.5.tgz", - "integrity": "sha512-f5lVcL/dG2kUHh8QFLakU722lgMwqXSjZUdmW6QdOMmqcE8cgl+oN9qk/qYlCSBMsYA7uexwn3hIr4h0naoPlw==", - "dev": true - }, - "@cspell/dict-cpp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-4.0.1.tgz", - "integrity": "sha512-mD6mn0XFCqHCz2j6p/7OQm3yNFn1dlQq6vip1pLynvNWDRz5yKYDVRUQCTEORT7ThS0dLpI4BjCX84YUKNhibA==", - "dev": true - }, - "@cspell/dict-cryptocurrencies": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz", - "integrity": "sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w==", - "dev": true - }, - "@cspell/dict-csharp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz", - "integrity": "sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==", - "dev": true - }, - "@cspell/dict-css": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.1.tgz", - "integrity": "sha512-jxsncdeiN/wkZGqU8iLtn24n3e0Fwugj6T48rjWUItn/i3C9j2W7RXOVqd7ZIeWeV8ibyq0WWiwA8Ajg6XaKpA==", - "dev": true - }, - "@cspell/dict-dart": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.0.1.tgz", - "integrity": "sha512-YRuDX9k2qPSWDEsM26j8o7KMvaZ0DXc74ijK/VRwaksm1CBRPBW289pe2TE2K7y4SJjTKXgQ9urOVlozeQDpuA==", - "dev": true - }, - "@cspell/dict-django": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.0.1.tgz", - "integrity": "sha512-q3l7OH39qzeN2Y64jpY39SEAqki5BUzPTypnhzM40yT+LOGSWqSh9Ix5UecejtXPDVrD8vML+m7Bp5070h52HQ==", - "dev": true - }, - "@cspell/dict-docker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.5.tgz", - "integrity": "sha512-SNEohOScQ+0+y9dp/jKTx60OOJQrf5es5BJ32gh5Ck3jKXNo4wd9KLgPOmQMUpencb5SGjrBsC4rr1fyfCwytg==", - "dev": true - }, - "@cspell/dict-dotnet": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-4.0.1.tgz", - "integrity": "sha512-l11TqlUX8cDgsE/1Zrea1PqLn63s20MY3jKWMbQVB5DMDPDO2f8Pukckkwxq5p/cxDABEjuGzfF1kTX3pAakBw==", - "dev": true - }, - "@cspell/dict-elixir": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.1.tgz", - "integrity": "sha512-IejBqiTTWSXpvBm6yg4qUfnJR0LwbUUCJcK5wXOMKEJitu3yDfrT9GPc6NQJXgokbg9nBjEyxVIzNcLgx2x3/Q==", - "dev": true - }, - "@cspell/dict-en_us": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.1.4.tgz", - "integrity": "sha512-smRT8Rx38+z1kiNl3kBvadoPdYgxCovxw2rsuO4/XtLRlSEcGPQgYJ0CCdcXMd9bhMY5roXPCcvYkBsyUVvg4A==", - "dev": true - }, - "@cspell/dict-en-gb": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", - "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", - "dev": true - }, - "@cspell/dict-filetypes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.0.tgz", - "integrity": "sha512-Fiyp0z5uWaK0d2TfR9GMUGDKmUMAsOhGD5A0kHoqnNGswL2iw0KB0mFBONEquxU65fEnQv4R+jdM2d9oucujuA==", - "dev": true - }, - "@cspell/dict-fonts": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-3.0.0.tgz", - "integrity": "sha512-zTZni0AbwBVG1MKA0WpwPyIJPVF+gp6neXDQzHcu4RUnuQ4uDu0PVEuZjGHCJWwwFoR5JmkqZxVSg1y3ufJODA==", - "dev": true - }, - "@cspell/dict-fullstack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.0.1.tgz", - "integrity": "sha512-r077HcbxGQ0gSjs4eqryvb9cu8/Noe7pzl9QksxFIEaMgyP180DEaCLAOnat4KHl7X0wntipY+naY5PVRQUI9A==", - "dev": true - }, - "@cspell/dict-gaming-terms": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.4.tgz", - "integrity": "sha512-hbDduNXlk4AOY0wFxcDMWBPpm34rpqJBeqaySeoUH70eKxpxm+dvjpoRLJgyu0TmymEICCQSl6lAHTHSDiWKZg==", - "dev": true - }, - "@cspell/dict-git": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-2.0.0.tgz", - "integrity": "sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w==", - "dev": true - }, - "@cspell/dict-golang": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-5.0.1.tgz", - "integrity": "sha512-djsJC7OVKUpFdRm/aqBJEUSGP3kw/MDhAt7udYegnyQt2WjL3ZnVoG7r5eOEhPEEKzWVBYoi6UKSNpdQEodlbg==", - "dev": true - }, - "@cspell/dict-haskell": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.1.tgz", - "integrity": "sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ==", - "dev": true - }, - "@cspell/dict-html": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.2.tgz", - "integrity": "sha512-BskOE2K3AtGLkcjdJmo+H6/fjdfDP4XYAsEGXpB26rvdnXAnGEstE/Q8Do6UfJCvgOVYCpdUZLcMIEpoTy7QhQ==", - "dev": true - }, - "@cspell/dict-html-symbol-entities": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz", - "integrity": "sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==", - "dev": true - }, - "@cspell/dict-java": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.4.tgz", - "integrity": "sha512-43VrLOLcBxavv6eyL4BpsnHrhVOgyYYeJqQRJG5XKObcpWy3+Lpadj58CfTVOr7M/Je3pUpd4tvsUhf/lWXMVA==", - "dev": true - }, - "@cspell/dict-k8s": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.0.tgz", - "integrity": "sha512-XqIql+nd2DiuPuL+qPc24bN/L1mZY75kAYcuMBMW5iYgBoivkiVOg7br/aofX3ApajvHDln6tNkPZhmhsOg6Ww==", - "dev": true - }, - "@cspell/dict-latex": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-3.1.0.tgz", - "integrity": "sha512-XD5S3FY0DrYiun2vm/KKOkeaD30LXp9v5EzVTVQvmxqQrQh0HvOT3TFD7lgKbyzZaG7E+l3wS94uwwm80cOmuw==", - "dev": true - }, - "@cspell/dict-lorem-ipsum": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-3.0.0.tgz", - "integrity": "sha512-msEV24qEpzWZs2kcEicqYlhyBpR0amfDkJOs+iffC07si9ftqtQ+yP3lf1VFLpgqw3SQh1M1vtU7RD4sPrNlcQ==", - "dev": true - }, - "@cspell/dict-lua": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-3.0.0.tgz", - "integrity": "sha512-WOhSCgS5wMxkGQJ8siB90iTB9ElquJB7FeqYSbJqqs6cUwH8G7MM/CEDPL6h7vCo0+v3GuxQ8yKWDSUcUhz9Lg==", - "dev": true - }, - "@cspell/dict-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-4.0.2.tgz", - "integrity": "sha512-FEQJ4TnMcXEFslqBQkXa5HposMoCGsiBv2ux4IZuIXgadXeHKHUHk60iarWpjhzNzQLyN2GD7NoRMd12bK3Llw==", - "dev": true - }, - "@cspell/dict-npm": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.3.tgz", - "integrity": "sha512-fEX67zIJISbS3gXVk/y/ZUvDIVtjc/CYJK7Mz0iTVrmlCKnLiD41lApe8v4g/12eE7hLfx/sfCXDrUWyzXVq1A==", - "dev": true - }, - "@cspell/dict-php": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-3.0.4.tgz", - "integrity": "sha512-QX6zE/ZfnT3O5lSwV8EPVh8Va39ds34gSNNR8I4GWiuDpKcTkZPFi4OLoP3Tlhbl/3G0Ha35OkSDLvZfu8mnkA==", - "dev": true - }, - "@cspell/dict-powershell": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-3.0.0.tgz", - "integrity": "sha512-pkztY9Ak4oc33q+Qxcn9/CTOKo4N8YIRRE6v67WwQOncA5QIJfcOPUrjfR3Z8SpzElXhu3s9qtWWSqbCy6qmcA==", - "dev": true - }, - "@cspell/dict-public-licenses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.1.tgz", - "integrity": "sha512-NZNwzkL5BqKddepDxvX/Qbji378Mso1TdnV4RFAN8hJoo6dSR0fv2TTI/Y0i/YWBmfmQGyTpEztBXtAw4qgjiA==", - "dev": true - }, - "@cspell/dict-python": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.0.1.tgz", - "integrity": "sha512-1wtUgyaTqRiQY0/fryk0oW22lcxNUnZ5DwteTzfatMdbgR0OHXTlHbI8vYxpHLWalSoch7EpLsnaymG+fOrt8g==", - "dev": true - }, - "@cspell/dict-r": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.0.1.tgz", - "integrity": "sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==", - "dev": true - }, - "@cspell/dict-ruby": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-3.0.0.tgz", - "integrity": "sha512-sA98T8Y1Pmq3RStVkO14E8vTWkq6JUn8c8PldiMyYgV0yfQgwhQfFAzlSfF3Gg2B0VkIdqt2et2SPN7f9wp7fQ==", - "dev": true - }, - "@cspell/dict-rust": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-3.0.0.tgz", - "integrity": "sha512-L1T1IBsYJZVDmfOGAbVLcpc6arWxRRCSJYvHSwEDBGrNuMyJ4jx/NvBEz5crcKf4vVKgwVlXgzQlJJZ8AVxU9w==", - "dev": true - }, - "@cspell/dict-scala": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-3.0.0.tgz", - "integrity": "sha512-sIiCQDIMMnNns/fzD61z5npbh5pypaKq07Orqe0+eRfdQpika8iRSGUGFHVbtdd1JzB1DyTCV2e8OwdaQiXqJQ==", - "dev": true - }, - "@cspell/dict-software-terms": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.0.8.tgz", - "integrity": "sha512-otq0yIcG19rNXkmE/EGWgUK7ClLrn/BE4n5Di3HKLw6XEp0sNBp1DKf88bg0LvbWh15uCAJ5xKAzF1sVPy2Y3w==", - "dev": true - }, - "@cspell/dict-sql": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.0.1.tgz", - "integrity": "sha512-7fvVcvy751cl31KMD5j04yMGq2UKj018/1hx3FNtdUI9UuUTMvhBrTAqHEEemR3ZeIC9i/5p5SQjwQ13bn04qw==", - "dev": true - }, - "@cspell/dict-svelte": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.2.tgz", - "integrity": "sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q==", - "dev": true - }, - "@cspell/dict-swift": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.1.tgz", - "integrity": "sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==", - "dev": true - }, - "@cspell/dict-typescript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.0.tgz", - "integrity": "sha512-4hdLlQMOYrUbGfJg2cWnbsBUevObwgL76TLVC0rwnrkSwzOxAxiGaG39VtRMvgAAe2lX6L+jka3fy0MmxzFOHw==", - "dev": true - }, - "@cspell/dict-vue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.0.tgz", - "integrity": "sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==", - "dev": true - }, - "@cspell/strong-weak-map": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-6.18.1.tgz", - "integrity": "sha512-etyMLISiDzgFf1BSGpUBD62cHp9NrCyrOi+iT7WrJ+My0l6IPRIhANuAVp2JcsXxe28en4X3Bp/egd46Q5Rpkg==", - "dev": true - }, "@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -10982,6 +10474,213 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "@inquirer/checkbox": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", + "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + } + }, + "@inquirer/confirm": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + } + }, + "@inquirer/core": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "requires": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "@inquirer/editor": { + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", + "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", + "requires": { + "@inquirer/core": "^10.2.0", + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" + } + }, + "@inquirer/expand": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", + "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + } + }, + "@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "requires": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + } + }, + "@inquirer/figures": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==" + }, + "@inquirer/input": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", + "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + } + }, + "@inquirer/number": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", + "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + } + }, + "@inquirer/password": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", + "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2" + } + }, + "@inquirer/prompts": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.0.tgz", + "integrity": "sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw==", + "requires": { + "@inquirer/checkbox": "^4.2.0", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.15", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" + } + }, + "@inquirer/rawlist": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", + "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + } + }, + "@inquirer/search": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.0.tgz", + "integrity": "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + } + }, + "@inquirer/select": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", + "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + } + }, + "@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "requires": {} + }, "@jridgewell/gen-mapping": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", @@ -11045,7 +10744,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -11054,14 +10752,12 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -11098,7 +10794,7 @@ "version": "20.19.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", - "dev": true, + "devOptional": true, "requires": { "undici-types": "~6.21.0" } @@ -11274,11 +10970,25 @@ "uri-js": "^4.2.2" } }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -11330,12 +11040,6 @@ "math-intrinsics": "^1.1.0" } }, - "array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true - }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -11513,7 +11217,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "requires": { "fill-range": "^7.1.1" } @@ -11602,16 +11305,29 @@ "supports-color": "^5.3.0" } }, - "clear-module": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", - "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", - "dev": true, + "chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==" + }, + "cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "requires": { - "parent-module": "^2.0.0", - "resolve-from": "^5.0.0" + "restore-cursor": "^5.0.0" } }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==" + }, + "cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==" + }, "cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -11650,20 +11366,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "comment-json": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", - "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", - "dev": true, - "requires": { - "array-timsort": "^1.0.3", - "core-util-is": "^1.0.3", - "esprima": "^4.0.1", - "has-own-prop": "^2.0.0", - "repeat-string": "^1.6.1" - } + "dev": true }, "concat-map": { "version": "0.0.1", @@ -11671,20 +11374,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, "convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -11700,24 +11389,6 @@ "browserslist": "^4.25.1" } }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", - "dev": true, - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - }, "cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -11729,96 +11400,6 @@ "which": "^2.0.1" } }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "cspell-dictionary": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.18.1.tgz", - "integrity": "sha512-q+tK+MWvJs9xL8wv79YlGPddUFb3Usuqh+VB8D0Zs7Xlsa/cw9bljRluHkpQrNr8APdZijGlgQP8L0cEr0/rEw==", - "dev": true, - "requires": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "cspell-trie-lib": "6.18.1", - "fast-equals": "^4.0.3", - "gensequence": "^4.0.3" - } - }, - "cspell-glob": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.18.1.tgz", - "integrity": "sha512-6dBBtQ1lRnVPoM13GOv7mJflkIvEr93TN96saQPWoaQqX8jwmklcMmDUndIkLcA7TnyxBbi3Z3X+s68zj/YGqw==", - "dev": true, - "requires": { - "micromatch": "^4.0.5" - } - }, - "cspell-grammar": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.18.1.tgz", - "integrity": "sha512-QPjOA9xwDPb3aoJXUOdL2aWX2wt8lPD7CoDROo8uruOXHAQzIY56q12EBy3jLIkxJFl9KAwtlEHkbLaJfTpIpg==", - "dev": true, - "requires": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1" - } - }, - "cspell-io": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.18.1.tgz", - "integrity": "sha512-WIfiDdG/7235CbkrjKPYIkP9oT8VvWXVTAeq6JkJPH7bm2A/CoE8ClieVsbbJnPyJnetnCuOuuz/zmuheVD02g==", - "dev": true, - "requires": { - "@cspell/cspell-service-bus": "6.18.1", - "node-fetch": "^2.6.7" - } - }, - "cspell-lib": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.18.1.tgz", - "integrity": "sha512-4MGjp51Ed8BbMPGXgqLGgUiWyb2DbOxgVEuWm8nxumxu7UmAWDBdMiD3QlY+ZYmfOJEVSa/kG7DTMrLQoeFwnQ==", - "dev": true, - "requires": { - "@cspell/cspell-bundled-dicts": "6.18.1", - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "@cspell/strong-weak-map": "6.18.1", - "clear-module": "^4.1.2", - "comment-json": "^4.2.3", - "configstore": "^5.0.1", - "cosmiconfig": "^8.0.0", - "cspell-dictionary": "6.18.1", - "cspell-glob": "6.18.1", - "cspell-grammar": "6.18.1", - "cspell-io": "6.18.1", - "cspell-trie-lib": "6.18.1", - "fast-equals": "^4.0.3", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "gensequence": "^4.0.3", - "import-fresh": "^3.3.0", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0", - "vscode-languageserver-textdocument": "^1.0.8", - "vscode-uri": "^3.0.7" - } - }, - "cspell-trie-lib": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.18.1.tgz", - "integrity": "sha512-rV32bqchz0uYdK6uafaw5QnYImRWQMcT2RNbBo0LXN6XoYoTSgpnPWTxQauNLxOm1m+dfb3GdasoAsjgWkPGnQ==", - "dev": true, - "requires": { - "@cspell/cspell-pipe": "6.18.1", - "@cspell/cspell-types": "6.18.1", - "fs-extra": "^11.1.0", - "gensequence": "^4.0.3" - } - }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -11939,15 +11520,6 @@ "esutils": "^2.0.2" } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, "dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -11980,15 +11552,6 @@ "tapable": "^2.2.0" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -13107,12 +12670,6 @@ "eslint-visitor-keys": "^3.4.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -13149,17 +12706,10 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-equals": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", - "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==", - "dev": true - }, "fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -13172,7 +12722,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -13195,7 +12744,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -13213,7 +12761,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -13254,17 +12801,6 @@ "is-callable": "^1.2.7" } }, - "fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -13303,12 +12839,6 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, - "gensequence": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.3.tgz", - "integrity": "sha512-izr+MKqJKjexkvLiPGhW96elQX8TuUR/su/xzILxjqzU1RDz1n1ZbqwDUnNFaRcq0gFR3oQfNH2JOH4Je1x/QA==", - "dev": true - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -13417,15 +12947,6 @@ "is-glob": "^4.0.3" } }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, "globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -13497,12 +13018,6 @@ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, - "has-own-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", - "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", - "dev": true - }, "has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -13545,6 +13060,14 @@ "function-bind": "^1.1.2" } }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -13600,11 +13123,19 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "inquirer": { + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.0.tgz", + "integrity": "sha512-LlFVmvWVCun7uEgPB3vups9NzBrjJn48kRNtFGw3xU1H5UXExTEz/oF1JGLaB0fvlkUB+W6JfgLcSEaSdH7RPA==", + "requires": { + "@inquirer/core": "^10.1.15", + "@inquirer/prompts": "^7.8.0", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^4.0.5", + "rxjs": "^7.8.2" + } }, "internal-slot": { "version": "1.1.0", @@ -13638,12 +13169,6 @@ "get-intrinsic": "^1.2.6" } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", @@ -13715,8 +13240,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-finalizationregistry": { "version": "1.1.1", @@ -13727,6 +13251,11 @@ "call-bound": "^1.0.3" } }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, "is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -13743,11 +13272,15 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==" + }, "is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -13763,8 +13296,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.1.1", @@ -13776,12 +13308,6 @@ "has-tostringtag": "^1.0.2" } }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, "is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -13845,11 +13371,10 @@ "which-typed-array": "^1.1.16" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==" }, "is-weakmap": { "version": "2.0.2", @@ -13929,12 +13454,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -13953,16 +13472,6 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, "jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -14009,12 +13518,6 @@ "type-check": "~0.4.0" } }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -14047,6 +13550,27 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "requires": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "dependencies": { + "chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==" + }, + "is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==" + } + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -14065,23 +13589,6 @@ "yallist": "^3.0.2" } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, "math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -14091,19 +13598,22 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "requires": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, + "mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==" + }, "minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -14125,21 +13635,17 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, "node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -14244,6 +13750,14 @@ "wrappy": "1" } }, + "onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "requires": { + "mimic-function": "^5.0.0" + } + }, "optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -14258,6 +13772,42 @@ "word-wrap": "^1.2.5" } }, + "ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "requires": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==" + }, + "chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==" + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -14289,27 +13839,6 @@ } } }, - "parent-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", - "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", - "dev": true, - "requires": { - "callsites": "^3.1.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -14349,8 +13878,7 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "possible-typed-array-names": { "version": "1.1.0", @@ -14365,9 +13893,9 @@ "dev": true }, "prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true }, "prop-types": { @@ -14390,8 +13918,7 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "react-is": { "version": "16.13.1", @@ -14506,12 +14033,6 @@ } } }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true - }, "resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -14523,32 +14044,32 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "requires": { - "global-dirs": "^0.1.1" - } - }, "resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true }, + "restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "requires": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + } + } + }, "reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" }, "rimraf": { "version": "3.0.2", @@ -14559,15 +14080,27 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.5.tgz", + "integrity": "sha512-oN9GTgxUNDBumHTTDmQ8dep6VIJbgj9S3dPP+9XylVLIK4xB9XTXtKWROd5pnhdXR9k0EgO1JRcNh0T+Ny2FsA==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "requires": { "queue-microtask": "^1.2.2" } }, + "rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "requires": { + "tslib": "^2.1.0" + } + }, "safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -14611,6 +14144,11 @@ "is-regex": "^1.2.1" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "scslre": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", @@ -14728,12 +14266,6 @@ "side-channel-map": "^1.0.1" } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -14754,6 +14286,11 @@ "source-map": "^0.6.0" } }, + "stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==" + }, "stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -14873,7 +14410,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -14921,17 +14457,10 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, "ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -14979,6 +14508,11 @@ } } }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -15047,15 +14581,6 @@ "reflect.getprototypeof": "^1.0.6" } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", @@ -15090,7 +14615,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true + "devOptional": true }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -15120,21 +14645,6 @@ "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, "update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -15154,18 +14664,6 @@ "punycode": "^2.1.0" } }, - "vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", - "dev": true - }, - "vscode-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.7.tgz", - "integrity": "sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==", - "dev": true - }, "vue-eslint-parser": { "version": "9.4.3", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", @@ -15181,22 +14679,6 @@ "semver": "^7.3.6" } }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -15309,24 +14791,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -15361,6 +14825,11 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==" } } } diff --git a/package.json b/package.json index 0145d94..c8bb07d 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "type": "module", "scripts": { "build": "tsc", - "prettier:check": "prettier --ignore-path .gitignore --check '**/*.{ts,js,json,md}'", - "prettier:fix": "npm run prettier:check -- --write '**/*.{ts,js,json,md}'", + "prettier:check": "prettier --ignore-path .gitignore --check '**/*.{ts,js,json,jsonc,md}'", + "prettier:fix": "npm run prettier:check -- --write '**/*.{ts,js,json,jsonc,md}'", "lint:check": "eslint --ignore-path .gitignore 'src/**/*.ts' -f codeframe", "lint:fix": "npm run lint:check -- --fix" }, @@ -27,14 +27,17 @@ }, "homepage": "https://github.com/AckeeCZ/create-node-app#readme", "devDependencies": { - "@ackee/styleguide-backend-config": "^1.0.0", + "@ackee/styleguide-backend-config": "^1.0.1", "@types/lodash-es": "^4.17.12", "@types/node": "^20.19.0", "@types/yargs": "^17.0.33", - "prettier": "^2.8.1", + "prettier": "^3.0.0", "typescript": "^5.4.5" }, "dependencies": { + "fast-glob": "^3.3.3", + "inquirer": "^12.9.0", + "ora": "^8.2.0", "source-map-support": "^0.5.21", "yargs": "^18.0.0", "lodash-es": "^4.17.21" diff --git a/src/Bootstrap.ts b/src/Bootstrap.ts index 80895de..d4ea29c 100644 --- a/src/Bootstrap.ts +++ b/src/Bootstrap.ts @@ -1,99 +1,140 @@ -import { CloudRunStarter } from './cloudrun/CloudRunStarter.js' -import { Npm } from './Npm.js' -import { Toolbelt } from './Toolbelt.js' +import inquirer from 'inquirer' import * as path from 'path' -import { PackageJson } from './PackageJson.js' -import { GraphQLStarter } from './cloudrun-graphql/GraphQLStarter.js' -import { Path } from './types.js' +import * as fs from 'fs' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' -import { logger } from './Logger.js' -import { Starter } from './Starter.js' +import { Builder } from './Builder.js' +import { Logger } from './Logger.js' +import { Npm } from './Npm.js' +import { PackageJson } from './PackageJson.js' +import { LoadedStarter, StarterLoader } from './StarterLoader.js' +import { Path } from './types.js' + +interface ParsedArgs { + dir: string + debug: boolean + force: boolean + projectName: string + [key: string]: unknown +} export class Bootstrap { - protected starters: Starter[] = [new CloudRunStarter(), new GraphQLStarter()] + protected starterLoader = new StarterLoader() - public runCLI(args: string[]) { - const cli = yargs(hideBin(args)) - .usage('create-node-app [options]') - .positional('starter', { + private async askMissingOptions(parsedArgs: ParsedArgs) { + const starters: LoadedStarter[] = [] + + for (const module of this.starterLoader.getOptions()) { + const moduleOption = parsedArgs[module.name.toLowerCase()] as string + if (moduleOption) { + if (moduleOption !== 'none') { + starters.push(this.starterLoader.getStarter(moduleOption)) + } + continue + } + + const answer = await inquirer.prompt<{ starter: string }>({ + type: 'list', name: 'starter', - type: 'string', - required: true, - description: 'Which template to setup (required)', - choices: this.starters.map(starter => starter.name), - }) - .option('dir', { - type: 'string', - alias: 'd', - default: './node-app', - description: 'Destination directory', + message: `Which ${module.name} would you like to use?`, + choices: [...module.starters, 'none'], }) - .option('project-name', { - type: 'string', - alias: 'n', - default: 'node-app', - description: 'Google Cloud project name', - }) - .option('force', { - type: 'boolean', - alias: 'f', - default: false, - description: - "Overwrite existing destination directory if it's not empty", - }) - .version('1.0.0') - .help() - const parsedArgs = cli.parseSync() - const starterArg = parsedArgs._[0] + if (answer.starter !== 'none') { + starters.push(this.starterLoader.getStarter(answer.starter)) + } + } + return starters + } - const starter = this.starters.find(x => x.name === starterArg) - const destination = path.normalize(parsedArgs.dir) as Path + public async runCLI(args: string[]) { + try { + let cli = yargs(hideBin(args)) + .usage('create-node-app [options]') + .option('dir', { + type: 'string', + alias: 'd', + default: './node-app', + description: 'Destination directory', + }) + .option('debug', { + type: 'boolean', + alias: 'D', + default: false, + description: 'Enables debug logs', + }) + .option('project-name', { + type: 'string', + alias: 'n', + default: 'node-app', + description: 'Google Cloud project name', + }) + .option('force', { + type: 'boolean', + alias: 'f', + default: false, + description: + "Overwrite existing destination directory if it's not empty", + }) - if (!starter) { - logger.info('Invalid starter') - cli.showHelp() - process.exit(1) - } + const starterOptions = this.starterLoader.getOptions() + for (const module of starterOptions) { + cli = cli.option(module.name.toLowerCase(), { + type: 'string', + choices: ['none', ...module.starters], + description: `Selects ${module.name}`, + }) + } + + cli = cli + .version('1.0.0') + .help() + .check(argv => { + for (const [key, val] of Object.entries(argv)) { + if (Array.isArray(val) && key !== '_') { + throw new Error(`Option --${key} specified multiple times`) + } + } + return true + }) + + const parsedArgs = cli.parseSync() + + const destination = path.normalize(parsedArgs.dir) as Path - logger.info(`starter=${starter.name}, destination=${destination}`) - - const npm = new Npm({ dir: destination }) - const packageJson = new PackageJson(npm) - const toolbelt = new Toolbelt({ - npm, - packageJson, - assetDirectory: path.join( - import.meta.dirname, - '..', - 'starter', - starter.name - ), - sharedDirectory: path.join( - import.meta.dirname, - '..', - 'starter', - 'shared' - ), - destination: destination, - projectName: parsedArgs.projectName, - }) - starter.setToolbelt(toolbelt) - - if (!toolbelt.isDirectoryEmpty(destination)) { - if (!parsedArgs.force) { - logger.info( - `Directory '${destination}' already exists and is not empty. Use --force or -f flag to overwrite the existing directory.` - ) - process.exit(1) + const logger = new Logger(parsedArgs.debug) + const npm = new Npm({ dir: destination, logger }) + const packageJson = new PackageJson(npm, logger) + + if (fs.existsSync(destination) && !parsedArgs.force) { + const answer = await inquirer.prompt<{ force: boolean }>({ + type: 'confirm', + name: 'force', + message: `Destination directory "${destination}" already exists. Do you want to overwrite everything in it?`, + }) + if (!answer.force) { + process.exit(0) + } + } + + const starters = await this.askMissingOptions(parsedArgs) + + const builder = new Builder({ + npm, + logger, + packageJson, + starters, + destination: destination, + projectName: parsedArgs.projectName, + }) + + await builder.build() + } catch (error) { + if (error instanceof Error && error.name === 'ExitPromptError') { + process.exit(0) } else { - logger.info(`Overwriting existing directory '${destination}'`) + throw error } } - - toolbelt.mkdir(destination, { overwrite: parsedArgs.force }) - toolbelt.npm.init() - starter.install() } } diff --git a/src/Builder.ts b/src/Builder.ts new file mode 100644 index 0000000..d377516 --- /dev/null +++ b/src/Builder.ts @@ -0,0 +1,172 @@ +import glob from 'fast-glob' +import * as fs from 'fs/promises' +import * as path from 'path' +import { Logger } from './Logger.js' +import { Npm } from './Npm.js' +import { PackageJson } from './PackageJson.js' +import { LoadedStarter, StarterConfig } from './StarterLoader.js' +import { Merger } from './Mergers/Merger.js' +import { PackageJsonMerger } from './Mergers/PackageJsonMerger.js' +import { EnvJsoncMerger } from './Mergers/EnvJsoncMerger.js' +import { ConfigMerger } from './Mergers/ConfigMerger.js' +import { ContainerMerger } from './Mergers/ContainerMerger.js' +import { Files } from './Files.js' + +export class Builder { + public static readonly BASE_STARTER_DIR = path.normalize( + path.join(import.meta.dirname, '..', 'starter', '_base') + ) + public static readonly IGNORED_FILES = ['node-app.jsonc'] + + public readonly npm: Npm + protected readonly logger: Logger + protected readonly starters: LoadedStarter[] + protected readonly fileMergers: Merger[] + protected readonly destination: string + protected readonly projectName: string + protected readonly replacements: Record + + constructor(params: { + npm: Npm + logger: Logger + packageJson: PackageJson + starters: LoadedStarter[] + destination: string + projectName: string + }) { + this.npm = params.npm + this.logger = params.logger + this.starters = params.starters + this.destination = params.destination + this.projectName = params.projectName + this.replacements = { + '{{PROJECT_NAME}}': this.projectName, + } + this.fileMergers = [ + new PackageJsonMerger(this.projectName, this.destination, 'package.json'), + new EnvJsoncMerger(this.destination, '.env.jsonc'), + new ConfigMerger(this.destination, 'src/config.ts'), + new ContainerMerger(this.destination, 'src/container.ts'), + ] + } + + protected async prepareFolder() { + if (await Files.existsAndIsDir(this.destination)) { + await fs.rm(this.destination, { recursive: true }) + } + await fs.mkdir(this.destination, { recursive: true }) + } + + public async build() { + try { + await this.logger.loader(`Preparing clean folder`, this.prepareFolder()) + + await this.logger.loader( + `Preparing folder structure`, + this.buildStarter(Builder.BASE_STARTER_DIR) + ) + + for (const starter of this.starters) { + await this.logger.loader( + `Adding ${starter.config.name} ${starter.config.module}`, + this.buildStarter(starter.path, starter.config) + ) + } + + await this.logger.loader(`npm install`, this.npm.run(['install'])) + + const prebuildScripts: Array = this.starters + .map(starter => starter.config.prebuild) + .filter(script => script !== undefined) + + for (const script of prebuildScripts) { + await this.logger.loader( + `npm run ${script.join(' ')}`, + this.npm.run(['run', ...script]) + ) + } + + await this.logger.loader(`npm run build`, this.npm.run(['run', 'build'])) + + this.logger.info( + `Your app is ready in ${path.relative( + process.cwd(), + this.destination + )}! 🚀` + ) + } catch (error) { + this.logger.error(error) + process.exit(1) + } + } + + protected async buildStarter(starterDir: string, config?: StarterConfig) { + const destDir = path.normalize(path.resolve(this.destination)) + const files = await glob(`${starterDir}/*`, { + cwd: starterDir, + dot: true, + onlyFiles: false, + }) + + const ignoredFiles = Builder.IGNORED_FILES.map(file => + path.join(starterDir, file) + ) + + const mergedFiles = await Promise.all( + this.fileMergers.map(async merger => { + return { + path: merger.getDestPath(), + content: await merger.merge(starterDir), + } + }) + ) + + await Promise.all( + files.map(async filePath => { + if (ignoredFiles.includes(filePath)) { + return + } + const destFilePath = path.join(destDir, path.basename(filePath)) + if (await Files.existsAndIsDir(filePath)) { + await fs.cp(filePath, destFilePath, { recursive: true }) + return + } + await fs.cp(filePath, destFilePath) + }) + ) + + await Promise.all( + mergedFiles.map(async ({ path, content }) => fs.writeFile(path, content)) + ) + + if (config?.replace) { + await Promise.all( + config.replace.map(async filePath => this.replaceInFile(filePath)) + ) + } + } + + public async replaceInFile(filePath: string) { + filePath = path.normalize(path.join(this.destination, filePath)) + let content = await Files.readUtf8File(filePath) + content = Object.keys(this.replacements).reduce((acc, key) => { + return acc.replaceAll(key, this.replacements[key]) + }, content) + return fs.writeFile(filePath, content) + } + + public async symlink(linkName: string, linkedFile: string) { + linkName = path.normalize(linkName) + linkedFile = path.normalize(linkedFile) + this.logger.info(`> ln -s ${linkName} ${linkedFile}`) + try { + await fs.symlink(linkedFile, linkName) + } catch (error) { + if ('code' in error && error.code === 'EEXIST') { + // OK + } else { + throw error + } + } + } +} diff --git a/src/Files.ts b/src/Files.ts new file mode 100644 index 0000000..56e6bf6 --- /dev/null +++ b/src/Files.ts @@ -0,0 +1,22 @@ +import * as fsp from 'fs/promises' +import path from 'path' + +export class Files { + public static async exists(filepath: string) { + const stat = await fsp.stat(filepath).catch(() => undefined) + return Boolean(stat) + } + + public static async existsAndIsDir(filepath: string) { + const stat = await fsp.stat(filepath).catch(() => undefined) + return Boolean(stat?.isDirectory()) + } + public static async readUtf8File(filepath: string) { + return fsp.readFile(filepath, 'utf8') + } + public static isInSameTree(tree: string, filepath: string) { + const file = path.normalize(filepath) + const fileTree = path.normalize(tree) + return file.startsWith(fileTree) + } +} diff --git a/src/Logger.ts b/src/Logger.ts index 0265f8b..991dda2 100644 --- a/src/Logger.ts +++ b/src/Logger.ts @@ -1,11 +1,30 @@ -export const logger = { - info: (message: string) => { +import { oraPromise } from 'ora' + +export class Logger { + constructor(public readonly enableDebug: boolean = false) {} + + info(message: string) { console.log(message) - }, - verbose: (message: string) => { + } + verbose(message: string) { console.log(message) - }, - error: (message: string) => { + } + error(message: string) { console.log(message) - }, + } + debug(message: string) { + if (this.enableDebug) { + console.log(message) + } + } + loader(message: string, promise: Promise) { + if (this.enableDebug) { + this.info(message) + return promise + } + + return oraPromise(promise, { + text: message, + }) + } } diff --git a/src/Mergers/ConfigMerger.ts b/src/Mergers/ConfigMerger.ts new file mode 100644 index 0000000..81a9270 --- /dev/null +++ b/src/Mergers/ConfigMerger.ts @@ -0,0 +1,28 @@ +import { Files } from '../Files.js' +import { Merger } from './Merger.js' + +export class ConfigMerger extends Merger { + name = 'Config' + + async merge(originDir: string): Promise { + const content = await this.getWhichExistsOrNull(originDir) + if (content) { + return content + } + + const { originPath, destPath } = this.getPaths(originDir) + + const [destTsConfig, originTsConfig] = await Promise.all([ + Files.readUtf8File(destPath), + Files.readUtf8File(originPath), + ]) + const configContent = /configSchema = {\n(.*?)\n}\n/s.exec( + originTsConfig + )?.[1] + + return destTsConfig.replace( + '\n}\n', + configContent ? `${configContent}\n}\n` : '}\n' + ) + } +} diff --git a/src/Mergers/ContainerMerger.ts b/src/Mergers/ContainerMerger.ts new file mode 100644 index 0000000..2d5b990 --- /dev/null +++ b/src/Mergers/ContainerMerger.ts @@ -0,0 +1,241 @@ +import { Merger } from './Merger.js' +import * as ts from 'typescript' +import { Files } from '../Files.js' + +export class ContainerMerger extends Merger { + async merge(originDir: string): Promise { + const content = await this.getWhichExistsOrNull(originDir) + if (content) { + return content + } + + const { originPath, destPath } = this.getPaths(originDir) + + const [originContainer, destContainer] = await Promise.all([ + Files.readUtf8File(originPath), + Files.readUtf8File(destPath), + ]) + + const originAst = this.parseFile(originContainer) + const destAst = this.parseFile(destContainer) + + const mergedImports = this.mergeImports(originAst, destAst) + const mergedInterface = this.mergeInterface(originAst, destAst) + const mergedFunction = this.mergeFunction(originAst, destAst) + + return `${mergedImports}\n\n${mergedInterface}\n\nexport type ContainerFactory = () => Promise\n\n${mergedFunction}\n` + } + + protected parseFile(content: string): ts.SourceFile { + return ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true) + } + + protected mergeImports( + originAst: ts.SourceFile, + destAst: ts.SourceFile + ): string { + const imports: string[] = [] + + const addImports = (node: ts.Node) => { + if (!ts.isImportDeclaration(node)) { + node.forEachChild(addImports) + return + } + + const importText = node.getText() + if (!imports.includes(importText)) { + imports.push(importText) + } + + node.forEachChild(addImports) + } + + addImports(originAst) + addImports(destAst) + + return imports.join('\n') + } + + protected mergeInterface( + originAst: ts.SourceFile, + destAst: ts.SourceFile + ): string { + const properties: string[] = [] + + const extractProperties = (node: ts.Node) => { + if (!ts.isInterfaceDeclaration(node) || node.name.text !== 'Container') { + node.forEachChild(extractProperties) + return + } + + node.members.forEach(member => { + if (!ts.isPropertySignature(member)) { + return + } + + const propText = member.getText().trim() + if (!properties.includes(propText)) { + properties.push(propText) + } + }) + + node.forEachChild(extractProperties) + } + + extractProperties(originAst) + extractProperties(destAst) + + return `export interface Container {\n ${properties.join('\n ')}\n}` + } + + protected mergeFunction( + originAst: ts.SourceFile, + destAst: ts.SourceFile + ): string { + const originFunctionBody = this.extractFunctionBody(originAst) + const destFunctionBody = this.extractFunctionBody(destAst) + + const allFunctionContent = [ + ...originFunctionBody.content, + ...destFunctionBody.content, + ] + + const mergedReturnProps = this.mergeReturnProperties( + originFunctionBody.returnProps, + destFunctionBody.returnProps + ) + + let body = '' + if (allFunctionContent.length > 0) { + body += allFunctionContent.join('\n') + '\n\n' + } + + body += ` return {\n ${mergedReturnProps.join(',\n ')}\n }` + + return `export const createContainer = async (): Promise => {\n${body}\n}` + } + + protected mergeReturnProperties( + originProps: ts.ObjectLiteralElementLike[], + destProps: ts.ObjectLiteralElementLike[] + ): string[] { + const mergedProps = new Map() + + originProps.forEach(prop => { + const propName = this.getPropertyName(prop) + if (propName) { + mergedProps.set(propName, prop) + } + }) + + destProps.forEach(prop => { + const propName = this.getPropertyName(prop) + if (propName) { + mergedProps.set(propName, prop) + } + }) + + return Array.from(mergedProps.values()).map(prop => { + const propText = prop.getText() + if ( + ts.isPropertyAssignment(prop) && + ts.isObjectLiteralExpression(prop.initializer) + ) { + return this.formatNestedObject(propText) + } + return propText + }) + } + + protected getPropertyName(prop: ts.ObjectLiteralElementLike): string | null { + if (ts.isPropertyAssignment(prop)) { + if (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) { + return prop.name.text + } + } else if (ts.isShorthandPropertyAssignment(prop)) { + return prop.name.text + } + return null + } + + protected formatNestedObject(propText: string): string { + const lines = propText.split('\n') + return lines + .map((line, index) => { + if (index === 0) { + return line + } + return ' ' + line + }) + .join('\n') + } + + protected extractFunctionBody(ast: ts.SourceFile): { + content: string[] + returnProps: ts.ObjectLiteralElementLike[] + } { + const content: string[] = [] + const returnProps: ts.ObjectLiteralElementLike[] = [] + + const visit = (node: ts.Node) => { + if (!this.isCreateContainer(node)) { + ts.forEachChild(node, visit) + return + } + + if (!node.initializer || !ts.isArrowFunction(node.initializer)) { + ts.forEachChild(node, visit) + return + } + + const body = node.initializer.body + if (!ts.isBlock(body)) { + ts.forEachChild(node, visit) + return + } + + body.statements.forEach(statement => { + if (this.isContentStatement(statement)) { + content.push(statement.getText().trim()) + } else if (this.isReturnWithObject(statement)) { + // Extract the actual property nodes, not just their names + statement.expression.properties.forEach(prop => { + returnProps.push(prop) + }) + } + }) + + ts.forEachChild(node, visit) + } + + visit(ast) + return { content, returnProps } + } + + protected isCreateContainer(node: ts.Node): node is ts.VariableDeclaration { + return ( + ts.isVariableDeclaration(node) && + node.name.getText() === 'createContainer' + ) + } + + protected isContentStatement(statement: ts.Statement): boolean { + return ( + ts.isVariableStatement(statement) || + (ts.isExpressionStatement(statement) && + ts.isCallExpression(statement.expression)) + ) + } + + protected isReturnWithObject( + statement: ts.Statement + ): statement is ts.ReturnStatement & { + expression: ts.ObjectLiteralExpression + } { + return ( + ts.isReturnStatement(statement) && + !!statement.expression && + ts.isObjectLiteralExpression(statement.expression) + ) + } +} diff --git a/src/Mergers/EnvJsoncMerger.ts b/src/Mergers/EnvJsoncMerger.ts new file mode 100644 index 0000000..5f3405d --- /dev/null +++ b/src/Mergers/EnvJsoncMerger.ts @@ -0,0 +1,24 @@ +import { Merger } from './Merger.js' +import { Files } from '../Files.js' + +export class EnvJsoncMerger extends Merger { + async merge(originDir: string): Promise { + const content = await this.getWhichExistsOrNull(originDir) + if (content) { + return content + } + + const { originPath, destPath } = this.getPaths(originDir) + + const [destEnvConfig, originEnvConfig] = await Promise.all([ + Files.readUtf8File(destPath), + Files.readUtf8File(originPath), + ]) + + const originWithoutOpenBracket = originEnvConfig.replace('{\n', '') + + return destEnvConfig + .replace(',\n}\n', '\n}\n') + .replace('\n}\n', `,\n${originWithoutOpenBracket}`) + } +} diff --git a/src/Mergers/Merger.ts b/src/Mergers/Merger.ts new file mode 100644 index 0000000..02d6f05 --- /dev/null +++ b/src/Mergers/Merger.ts @@ -0,0 +1,51 @@ +import path from 'path' +import { Files } from '../Files.js' + +export abstract class Merger { + abstract merge(originDir: string): Promise + + protected destPath: string + + constructor( + protected readonly destDir: string, + protected readonly pathToFile: string + ) { + this.destPath = path.join(this.destDir, this.pathToFile) + } + + public getDestPath() { + return this.destPath + } + + protected getPaths(originDir: string) { + return { + originPath: path.join(originDir, this.pathToFile), + destPath: this.getDestPath(), + } + } + + protected async getWhichExistsOrNull( + originDir: string + ): Promise { + const { originPath, destPath } = this.getPaths(originDir) + + const [originExists, destExists] = await Promise.all([ + Files.exists(originPath), + Files.exists(destPath), + ]) + + if (!originExists && destExists) { + return Files.readUtf8File(destPath) + } + + if (!destExists && originExists) { + return Files.readUtf8File(originPath) + } + + if (!originExists && !destExists) { + throw new Error(`No file found to merge: ${this.pathToFile}`) + } + + return null + } +} diff --git a/src/Mergers/PackageJsonMerger.ts b/src/Mergers/PackageJsonMerger.ts new file mode 100644 index 0000000..c06131e --- /dev/null +++ b/src/Mergers/PackageJsonMerger.ts @@ -0,0 +1,45 @@ +import { Merger } from './Merger.js' +import { Files } from '../Files.js' + +export class PackageJsonMerger extends Merger { + constructor( + private readonly projectName: string, + destDir: string, + pathToFile: string + ) { + super(destDir, pathToFile) + } + + async merge(originDir: string): Promise { + const content = await this.getWhichExistsOrNull(originDir) + if (content) { + return content + } + + const { originPath, destPath } = this.getPaths(originDir) + + const [destPckgJson, starterPckgJson] = await Promise.all([ + Files.readUtf8File(destPath), + Files.readUtf8File(originPath), + ]) + + const destPckgJsonObj = JSON.parse(destPckgJson) + const starterPckgJsonObj = JSON.parse(starterPckgJson) + + destPckgJsonObj.name = this.projectName + destPckgJsonObj.scripts = { + ...destPckgJsonObj.scripts, + ...starterPckgJsonObj.scripts, + } + destPckgJsonObj.dependencies = { + ...destPckgJsonObj.dependencies, + ...starterPckgJsonObj.dependencies, + } + destPckgJsonObj.devDependencies = { + ...destPckgJsonObj.devDependencies, + ...starterPckgJsonObj.devDependencies, + } + + return JSON.stringify(destPckgJsonObj, null, 2) + } +} diff --git a/src/Npm.ts b/src/Npm.ts index cde2762..7d093c0 100644 --- a/src/Npm.ts +++ b/src/Npm.ts @@ -1,27 +1,72 @@ import * as childProcess from 'child_process' -import { logger } from './Logger.js' +import { Logger } from './Logger.js' import { Path } from './types.js' +export class NpmError extends Error { + constructor( + message: string, + public readonly code: number | null + ) { + super(message) + this.name = 'NpmError' + } +} + export class Npm { + protected readonly logger: Logger public readonly dir: Path - constructor(settings?: { dir?: Path }) { + + constructor(settings?: { dir?: Path; logger?: Logger }) { + this.logger = settings?.logger ?? new Logger() this.dir = settings?.dir as Path } + + protected spawn( + cmd: string, + args: ReadonlyArray, + options: childProcess.SpawnOptions = {} + ) { + return new Promise((resolve, reject) => { + const cp = childProcess.spawn(cmd, args, options) + const error: string[] = [] + const stdout: string[] = [] + + cp.stdout?.on('data', data => { + stdout.push(data.toString()) + }) + + cp.on('error', e => { + error.push(e.toString()) + }) + + cp.on('close', code => { + if (error.length || (code !== null && code > 0)) { + reject( + new NpmError( + error.length ? error.join('') : stdout.join(''), + code ?? null + ) + ) + } else { + resolve(undefined) + } + }) + }) + } + public run(args: string[]) { - logger.info(`> npm ${args.join(' ')}`) - const result = this.dir - ? childProcess.spawnSync('npm', args, { + this.logger.debug(`> npm ${args.join(' ')}`) + const options: childProcess.SpawnOptions = this.dir + ? { cwd: this.dir, - }) - : childProcess.spawnSync('npm', args) - if ((result?.status ?? 0) > 0) { - logger.info( - `Failed npm command: npm ${args.join(' ')}. ${String(result.output)}` - ) - } + stdio: this.logger.enableDebug ? 'inherit' : 'pipe', + } + : { stdio: this.logger.enableDebug ? 'inherit' : 'pipe' } + + return this.spawn('npm', args, options) } public init() { - this.run(['init', '--yes']) + return this.run(['init', '--yes']) } public i(module?: string) { @@ -29,10 +74,10 @@ export class Npm { return this.run(['i']) } const args = ['i', module] - this.run(args) + return this.run(args) } public iDev(module: string) { const args = ['i', '-D', module] - this.run(args) + return this.run(args) } } diff --git a/src/PackageJson.ts b/src/PackageJson.ts index 0774b82..9b92d49 100644 --- a/src/PackageJson.ts +++ b/src/PackageJson.ts @@ -2,19 +2,21 @@ import * as path from 'path' import * as fs from 'fs' import * as lodash from 'lodash-es' import { Npm } from './Npm.js' -import { logger } from './Logger.js' import { Path } from './types.js' +import { Logger } from './Logger.js' export class PackageJson { public readonly path: Path protected npm: Npm - constructor(npm: Npm) { + protected logger: Logger + constructor(npm: Npm, logger: Logger) { let packagejsonPath = './package.json' as Path if (npm.dir) { packagejsonPath = path.normalize(`${npm.dir}/${packagejsonPath}`) as Path } this.path = packagejsonPath this.npm = npm + this.logger = logger } public setType(type: 'module' | 'commonjs') { this.mergeWith({ @@ -25,7 +27,7 @@ export class PackageJson { return JSON.parse(fs.readFileSync(this.path, 'utf-8')) } public runScript(name: string) { - this.npm.run(['run', name]) + return this.npm.run(['run', name]) } public addNpmScript(name: string, command: string) { this.mergeWith({ @@ -37,7 +39,7 @@ export class PackageJson { // Updated package json using merge with given object public mergeWith(partialWith: any) { const json = lodash.merge(this.toJSON(), partialWith) - logger.info(`> package.json updated ${JSON.stringify(partialWith)}`) + this.logger.debug(`> package.json updated ${JSON.stringify(partialWith)}`) fs.writeFileSync( path.join(this.path), JSON.stringify(json, null, 2), diff --git a/src/Starter.ts b/src/Starter.ts index 7a06f8f..a3f72a6 100644 --- a/src/Starter.ts +++ b/src/Starter.ts @@ -1,7 +1,7 @@ -import { Toolbelt } from './Toolbelt.js' +import { Builder } from './Builder.js' export interface Starter { readonly name: string - setToolbelt(toolbelt: Toolbelt): Starter + setToolbelt(toolbelt: Builder): Starter install(): void } diff --git a/src/StarterLoader.ts b/src/StarterLoader.ts new file mode 100644 index 0000000..8c7aba0 --- /dev/null +++ b/src/StarterLoader.ts @@ -0,0 +1,148 @@ +import glob from 'fast-glob' +import fs from 'node:fs' +import path from 'node:path' +import { Files } from './Files.js' + +export interface StarterConfig { + module: string + name: string + id: string + prebuild?: string[] + replace?: string[] + merge?: string[] +} + +export interface LoadedStarter { + name: string + config: StarterConfig + + path: string + configPath: string +} + +export interface StarterModule { + name: string + starters: string[] +} + +export class StarterLoader { + private static readonly starterPath: string = path.normalize( + path.join(import.meta.dirname, '..', 'starter') + ) + private readonly starters: Map = new Map() + private readonly modules: StarterModule[] = [] + + constructor() { + const configFiles = glob.sync( + `${StarterLoader.starterPath}/**/node-app.jsonc` + ) + + for (const configFile of configFiles) { + const config = StarterLoader.validateConfig( + configFile, + JSON.parse(fs.readFileSync(configFile, 'utf8')) + ) + + const original = this.starters.get(config.id) + if (original) { + throw new Error( + `Duplicate starter: ${config.name}\n` + + `> Starter 1: ${original.path}\n` + + `> Starter 2: ${path.dirname(configFile)}` + ) + } + + this.starters.set(config.id, { + name: config.name, + config, + path: path.dirname(configFile), + configPath: configFile, + }) + + const module = this.modules.find(module => module.name === config.module) + if (module) { + module.starters.push(config.id) + continue + } + this.modules.push({ + name: config.module, + starters: [config.id], + }) + } + + this.modules.sort((a, b) => a.name.localeCompare(b.name)) + } + + getOptions(): StarterModule[] { + return this.modules + } + + getStarter(id: string): LoadedStarter { + const starter = this.starters.get(id) + if (!starter) { + throw new Error(`Starter ${id} not found`) + } + return starter + } + + private static validateConfig( + configPath: string, + config: any + ): StarterConfig { + if (!config.module) { + throw new Error(`Invalid config at ${configPath}: module key is required`) + } + if (!config.name) { + throw new Error(`Invalid config at ${configPath}: name key is required`) + } + if (!config.id) { + throw new Error(`Invalid config at ${configPath}: id key is required`) + } + if (!StarterLoader.isValidOptionalStringArray(config.prebuild)) { + throw new Error( + `Invalid config at ${configPath}: "prebuild" must be array of npm script names or empty` + ) + } + + if (!StarterLoader.isValidOptionalStringArray(config.replace)) { + throw new Error( + `Invalid config at ${configPath}: "replace" must be array of files where strings should be replaced` + ) + } + if (config.replace) { + const configDir = path.dirname(configPath) + + const invalidReplace = config.replace.find((replace: string) => { + const replacePath = path.join(configDir, replace) + return ( + !fs.existsSync(replacePath) || + !Files.isInSameTree(configDir, path.join(configDir, replacePath)) + ) + }) + + if (invalidReplace) { + throw new Error( + `Invalid config at ${configPath}: "replace" must be array of files in the project directory, got: ${invalidReplace}` + ) + } + } + + const invalidKeys = Object.keys(config).filter( + key => !['module', 'name', 'prebuild', 'replace', 'id'].includes(key) + ) + if (invalidKeys.length > 0) { + throw new Error( + `Invalid config at ${configPath}: Unknown key(s): ${invalidKeys.join(', ')}` + ) + } + return config + } + + protected static isValidOptionalStringArray(array: any): array is string[] { + return ( + !array || + (Array.isArray(array) && + array.every((item: any) => typeof item === 'string')) + ) + } +} diff --git a/src/Toolbelt.ts b/src/Toolbelt.ts deleted file mode 100644 index afba9ce..0000000 --- a/src/Toolbelt.ts +++ /dev/null @@ -1,132 +0,0 @@ -import * as path from 'path' -import * as fs from 'fs' -import { PackageJson } from './PackageJson.js' -import { Npm } from './Npm.js' -import { logger } from './Logger.js' -import { Path } from './types.js' - -export class Toolbelt { - public readonly npm: Npm - public readonly packageJson: PackageJson - readonly assetDirectory: string - readonly sharedDirectory: string - readonly destination: string - readonly projectName?: string - constructor(params: { - npm: Npm - packageJson: PackageJson - assetDirectory: string - sharedDirectory: string - destination: string - projectName?: string - }) { - this.npm = params.npm - this.packageJson = params.packageJson - this.assetDirectory = params.assetDirectory - this.sharedDirectory = params.sharedDirectory - this.destination = params.destination - this.projectName = params.projectName - } - public stringToPath(str: string) { - return path.normalize(str) as Path - } - - public isDirectoryEmpty(dirpath: string): boolean { - const path = this.stringToPath(dirpath) - - if (!fs.existsSync(path)) { - return true - } - - const stat = fs.statSync(path) - if (!stat.isDirectory()) { - return true - } - - const contents = fs.readdirSync(path) - return contents.length === 0 - } - - public mkdir( - dirpath: string, - option?: { - /** If exists, remove recursively first */ - overwrite?: boolean - } - ) { - dirpath = this.stringToPath(dirpath) - const rootPath = ['.', './'] - if (!rootPath.includes(dirpath)) { - if (fs.existsSync(dirpath) && option?.overwrite) { - fs.rmSync(dirpath, { recursive: true }) - } - fs.mkdirSync(dirpath, { recursive: true }) - } - } - /** - * Like cp, but second argument does not need to include file name - * the name is preserved. - */ - public cpFile(a: string, b: string, option?: { destFileName?: string }) { - a = this.stringToPath(a) - b = this.stringToPath(b) - const file = path.basename(a) - this.cp(a, this.stringToPath(`${b}/${option?.destFileName ?? file}`)) - } - - public cp(a: string, b: string) { - a = this.stringToPath(a) - b = this.stringToPath(b) - logger.info(`> cp ${a} ${b}`) - fs.copyFileSync(a, b) - } - public copyAsset(name: string, destination?: string) { - let destinationName = name - if (path.basename(name) === '.gitignore') { - name = '.gitignore_' - destinationName = '.gitignore' - } - name = this.stringToPath(name) - destination = this.stringToPath(this.destination) - this.cpFile(`${this.assetDirectory}/${name}`, destination, { - destFileName: destinationName, - }) - } - public copySharedAsset(name: string, destination?: string) { - let destinationName = name - if (path.basename(name) === '.gitignore') { - name = '.gitignore_' - destinationName = '.gitignore' - } - name = this.stringToPath(name) - destination = this.stringToPath(this.destination) - this.cpFile(`${this.sharedDirectory}/${name}`, destination, { - destFileName: destinationName, - }) - } - public replaceInFile( - filePath: string, - placeholder: string, - replacement: string = 'REPLACEME' - ) { - filePath = this.stringToPath(`${this.destination}/${filePath}`) - let content = fs.readFileSync(filePath, 'utf8') - /* eslint-disable-next-line security/detect-non-literal-regexp */ - content = content.replace(new RegExp(placeholder, 'g'), replacement) - fs.writeFileSync(filePath, content) - } - public symlink(linkName: string, linkedFile: string) { - linkName = this.stringToPath(linkName) - linkedFile = this.stringToPath(linkedFile) - logger.info(`> ln -s ${linkName} ${linkedFile}`) - try { - fs.symlinkSync(linkedFile, linkName) - } catch (error) { - if ('code' in error && error.code === 'EEXIST') { - // OK - } else { - throw error - } - } - } -} diff --git a/src/cloudrun-graphql/GraphQLStarter.ts b/src/cloudrun-graphql/GraphQLStarter.ts deleted file mode 100644 index 36ec592..0000000 --- a/src/cloudrun-graphql/GraphQLStarter.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { Starter } from '../Starter.js' -import { Toolbelt } from '../Toolbelt.js' - -export class GraphQLStarter implements Starter { - public readonly name = 'cloudrun-graphql' - protected toolbelt?: Toolbelt - - public setToolbelt(toolbelt: Toolbelt): Starter { - this.toolbelt = toolbelt - return this - } - - public install(): void { - if (this.toolbelt == null) { - throw new Error('No toolbelt') - } - const tb = this.toolbelt - tb.copySharedAsset('.gitignore') - tb.copySharedAsset('.gitlab-ci.yml') - tb.copySharedAsset('.nvmrc') - tb.copySharedAsset('Dockerfile') - tb.copySharedAsset('.dockerignore') - - tb.mkdir(tb.stringToPath(`${tb.destination}/ci-branch-config`)) - tb.copySharedAsset('ci-branch-config/common.env') - tb.replaceInFile( - `ci-branch-config/common.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/development.env') - tb.replaceInFile( - `ci-branch-config/development.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/stage.env') - tb.replaceInFile( - `ci-branch-config/stage.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/master.env') - tb.replaceInFile( - `ci-branch-config/master.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - - tb.mkdir(tb.stringToPath(`${tb.destination}/docker-compose`)) - tb.copySharedAsset('docker-compose/docker-compose-entrypoint.sh') - tb.copySharedAsset('docker-compose/docker-compose.ci.yml') - tb.copySharedAsset('docker-compose/docker-compose.local.yml') - tb.copySharedAsset('docker-compose/docker-compose.override.yml') - tb.symlink( - `${tb.destination}/docker-compose/docker-compose.override.yml`, - `${tb.destination}/docker-compose/docker-compose.local.yml` - ) - tb.copySharedAsset('docker-compose/docker-compose.yml') - tb.replaceInFile( - `docker-compose/docker-compose.yml`, - '{{PROJECT_NAME}}', - tb.projectName - ) - - tb.npm.iDev('typescript') - tb.npm.iDev('@types/node') - tb.npm.iDev('ts-node') - tb.npm.i('source-map-support') - tb.copySharedAsset('tsconfig.json') - tb.packageJson.addNpmScript( - 'build:graphql-types', - 'graphql-codegen --config codegen.yml' - ) - tb.packageJson.addNpmScript( - 'build:copy-schema', - 'mkdir -p ./dist/view/graphql/schema && cp -r ./src/view/graphql/schema ./dist/view/graphql/schema' - ) - tb.packageJson.addNpmScript( - 'build', - 'npm run build:graphql-types && npm run build:copy-schema && tsc' - ) - tb.packageJson.addNpmScript( - 'start', - 'node -r source-map-support/register dist/index.js' - ) - - tb.npm.i('configuru') - tb.npm.i('pino') - tb.npm.iDev('pino-pretty') - tb.copyAsset('.env.jsonc') - tb.mkdir(tb.stringToPath(`${tb.destination}/src`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/errors`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/ports`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/utils`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/domain/errors/codes.ts') - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/ports/logger.d.ts') - tb.copyAsset('src/adapters/pino.logger.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql/resolvers`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/graphql/schema`)) - tb.copyAsset('src/config.ts') - tb.copyAsset('src/index.ts') - tb.copyAsset('src/container.ts') - tb.copyAsset('src/context.ts') - tb.copyAsset('codegen.yml') - - tb.copyAsset('src/view/controller.ts') - tb.copyAsset('src/view/server.ts') - tb.copyAsset('src/view/graphql/schema.ts') - tb.copyAsset('src/view/graphql/resolvers.ts') - tb.copyAsset('src/view/graphql/resolvers/greeting.resolver.ts') - tb.copyAsset('src/view/graphql/schema/schema.graphql') - - tb.npm.iDev('mocha') - tb.npm.iDev('mocha-junit-reporter') - tb.npm.iDev('mocha-multi-reporters') - tb.npm.iDev('nyc') - tb.npm.iDev('tsx') - tb.npm.iDev('@types/mocha') - tb.npm.iDev('@istanbuljs/nyc-config-typescript') - tb.copySharedAsset('.mocharc.json', tb.destination) - tb.copySharedAsset('.mocha-junit-config.json', tb.destination) - tb.packageJson.setType('module') - tb.packageJson.addNpmScript('test', 'mocha') - - tb.packageJson.addNpmScript( - 'ci-test:no-coverage', - 'npm run test -- --parallel=false -R mocha-multi-reporters --reporter-options configFile=.mocha-junit-config.json' - ) - tb.packageJson.addNpmScript( - 'ci-test', - 'nyc -a -r cobertura --report-dir output npm run ci-test:no-coverage' - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test`)) - tb.copySharedAsset('src/test/setup.ts') - tb.copyAsset('src/test/helloWorld.test.ts') - - tb.npm.i('@as-integrations/express5') - tb.npm.iDev('@ackee/styleguide-backend-config') - tb.npm.iDev('prettier') - tb.npm.iDev('eslint') - tb.npm.iDev('eslint-formatter-gitlab@^5.0.0') - tb.copyAsset('.eslint.tsconfig.json') - tb.copyAsset('.eslintrc.cjs') - tb.copySharedAsset('prettier.config.cjs') - - tb.packageJson.addNpmScript( - 'prettier', - "prettier --check --write '**/*.{ts,js,json,md}'" - ) - tb.packageJson.addNpmScript( - 'lint', - 'eslint --ext .ts --ext .graphql src -f codeframe --fix' - ) - tb.packageJson.addNpmScript('codestyle', 'npm run prettier && npm run lint') - tb.packageJson.addNpmScript( - 'ci-lint', - 'npm run lint -- -f checkstyle -o ./output/checkstyle-result.xml' - ) - - tb.npm.i('@apollo/server') - tb.npm.iDev('@graphql-codegen/cli') - tb.npm.iDev('lodash') - tb.npm.iDev('@graphql-eslint/eslint-plugin') - tb.npm.iDev('@graphql-codegen/typescript') - tb.npm.iDev('@graphql-codegen/typescript-resolvers') - tb.npm.i('@graphql-tools/load-files') - tb.npm.i('@graphql-tools/merge') - tb.npm.i('@graphql-tools/schema') - tb.npm.i('graphql') - tb.npm.i('express') - tb.npm.iDev('@types/express') - - tb.packageJson.runScript('build') - } -} diff --git a/src/cloudrun/CloudRunStarter.ts b/src/cloudrun/CloudRunStarter.ts deleted file mode 100644 index 7481dde..0000000 --- a/src/cloudrun/CloudRunStarter.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { Starter } from '../Starter.js' -import { Toolbelt } from '../Toolbelt.js' - -export class CloudRunStarter implements Starter { - public readonly name = 'cloudrun' - protected toolbelt?: Toolbelt - - public setToolbelt(toolbelt: Toolbelt): Starter { - this.toolbelt = toolbelt - return this - } - - public install(): void { - if (this.toolbelt == null) { - throw new Error('No toolbelt') - } - const tb = this.toolbelt - tb.copySharedAsset('.gitignore') - tb.copySharedAsset('.gitlab-ci.yml') - tb.copySharedAsset('.nvmrc') - tb.copySharedAsset('Dockerfile') - tb.copySharedAsset('.dockerignore') - - tb.mkdir(tb.stringToPath(`${tb.destination}/ci-branch-config`)) - tb.copySharedAsset('ci-branch-config/common.env') - tb.replaceInFile( - `ci-branch-config/common.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/development.env') - tb.replaceInFile( - `ci-branch-config/development.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/stage.env') - tb.replaceInFile( - `ci-branch-config/stage.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.copySharedAsset('ci-branch-config/master.env') - tb.replaceInFile( - `ci-branch-config/master.env`, - '{{PROJECT_NAME}}', - tb.projectName - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/docker-compose`)) - tb.copySharedAsset('docker-compose/docker-compose-entrypoint.sh') - tb.copySharedAsset('docker-compose/docker-compose.ci.yml') - tb.copySharedAsset('docker-compose/docker-compose.local.yml') - tb.symlink( - `${tb.destination}/docker-compose/docker-compose.override.yml`, - `${tb.destination}/docker-compose/docker-compose.local.yml` - ) - tb.copySharedAsset('docker-compose/docker-compose.yml') - tb.replaceInFile( - `docker-compose/docker-compose.yml`, - '{{PROJECT_NAME}}', - tb.projectName - ) - - tb.npm.iDev('typescript') - tb.npm.iDev('@types/node') - tb.npm.iDev('ts-node') - tb.npm.i('source-map-support') - tb.copySharedAsset('tsconfig.json') - tb.packageJson.setType('module') - tb.packageJson.addNpmScript('build', 'tsc') - tb.packageJson.addNpmScript( - 'start', - 'node -r source-map-support/register dist/index.js' - ) - - tb.npm.i('configuru') - tb.npm.i('pino') - tb.npm.i('pino-http') - tb.npm.iDev('pino-pretty') - tb.copyAsset('.env.jsonc') - tb.mkdir(tb.stringToPath(`${tb.destination}/src`)) - tb.copyAsset('src/config.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/container.ts') - tb.copyAsset('src/context.ts') - tb.copyAsset('src/index.ts') - - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view`)) - tb.copyAsset(`/src/view/server.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest`)) - tb.copyAsset(`/src/view/rest/request.d.ts`) - tb.copyAsset(`/src/view/rest/routes.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/controller`)) - tb.copyAsset(`/src/view/rest/controller/health-check.controller.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/middleware`)) - tb.copyAsset(`/src/view/rest/middleware/context-middleware.ts`) - tb.copyAsset(`/src/view/rest/middleware/error-handler.ts`) - tb.copyAsset(`/src/view/rest/middleware/request-logger.ts`) - - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/util`)) - tb.copyAsset(`/src/view/rest/util/openapi.util.ts`) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/rest/spec`)) - tb.copyAsset(`/src/view/rest/spec/openapi.yml`) - tb.npm.i('node-healthz') - - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain`)) - tb.copyAsset('src/domain/health-check.service.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/errors`)) - tb.copyAsset('src/domain/errors/errors.ts') - tb.copyAsset('src/domain/errors/codes.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/util`)) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/domain/ports`)) - tb.copyAsset('src/domain/ports/logger.d.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/adapters`)) - tb.copyAsset('src/adapters/pino.logger.ts') - - tb.npm.i('express') - tb.npm.iDev('@types/express') - - tb.npm.iDev('mocha') - tb.npm.iDev('mocha-junit-reporter') - tb.npm.iDev('mocha-multi-reporters') - tb.npm.iDev('nyc') - tb.npm.iDev('@types/mocha') - tb.npm.iDev('@istanbuljs/nyc-config-typescript') - tb.npm.iDev('supertest') - tb.npm.iDev('@types/supertest') - tb.copySharedAsset('.mocharc.json', tb.destination) - tb.copySharedAsset('.mocha-junit-config.json', tb.destination) - tb.packageJson.addNpmScript('test', 'mocha') - tb.packageJson.addNpmScript( - 'ci-test:no-coverage', - 'npm run test -- --parallel=false -R mocha-multi-reporters --reporter-options configFile=.mocha-junit-config.json' - ) - tb.packageJson.addNpmScript( - 'ci-test', - 'nyc -a -r cobertura --report-dir output npm run ci-test:no-coverage' - ) - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test`)) - tb.copySharedAsset('src/test/setup.ts') - tb.copyAsset('src/test/health-check.test.ts') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/test/util`)) - tb.copyAsset('src/test/util/openapi-test.util.ts') - - tb.npm.iDev('@ackee/styleguide-backend-config') - tb.npm.iDev('prettier') - tb.npm.iDev('eslint') - tb.npm.iDev('eslint-formatter-gitlab@^5.0.0') - tb.copyAsset('.eslint.tsconfig.json') - tb.copyAsset('.eslintrc.cjs') - tb.copySharedAsset('prettier.config.cjs') - tb.packageJson.addNpmScript( - 'prettier', - "prettier --check --write '**/*.{ts,js,json,md}'" - ) - tb.packageJson.addNpmScript('lint', "eslint '**/*.ts' -f codeframe --fix") - tb.packageJson.addNpmScript('codestyle', 'npm run prettier && npm run lint') - tb.packageJson.addNpmScript( - 'ci-lint', - 'npm run lint -- -f checkstyle -o ./output/checkstyle-result.xml' - ) - - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/cli`)) - tb.copyAsset('src/view/cli/cli.ts') - tb.copyAsset('src/view/cli/README.md') - tb.mkdir(tb.stringToPath(`${tb.destination}/src/view/cli/openapi`)) - tb.copyAsset('src/view/cli/openapi/generate.ts') - tb.npm.iDev('yargs') - tb.npm.iDev('@types/yargs') - tb.npm.iDev('yaml') - tb.packageJson.addNpmScript('cli', 'tsx ./src/view/cli/cli.ts') - tb.npm.iDev('openapi-typescript') - tb.npm.iDev('tsx') - tb.packageJson.addNpmScript( - 'generate:api', - 'npm run cli openapi generate src/view/rest/spec/openapi.yml && npm run codestyle' - ) - - tb.packageJson.runScript('generate:api') - tb.packageJson.runScript('build') - } -} diff --git a/starter/shared/.dockerignore b/starter/_base/.dockerignore similarity index 100% rename from starter/shared/.dockerignore rename to starter/_base/.dockerignore diff --git a/starter/cloudrun/.env.jsonc b/starter/_base/.env.jsonc similarity index 58% rename from starter/cloudrun/.env.jsonc rename to starter/_base/.env.jsonc index 67f8be0..fd6a1d1 100644 --- a/starter/cloudrun/.env.jsonc +++ b/starter/_base/.env.jsonc @@ -2,9 +2,5 @@ // Logging level, see https://github.com/pinojs/pino/blob/master/docs/api.md#logger-level "LOGGER_DEFAULT_LEVEL": "debug", // Enable/disable logging object multiline formatted logging https://github.com/pinojs/pino/blob/master/docs/api.md#prettyprint-boolean--object - "LOGGER_PRETTY": false, - // API server listening port. - "SERVER_PORT": 3000, - // Boolean to remove sensitive info from http error responses - "ENABLE_PRODUCTION_HTTP_ERROR_RESPONSES": false + "LOGGER_PRETTY": false } diff --git a/starter/cloudrun/.eslint.tsconfig.json b/starter/_base/.eslint.tsconfig.json similarity index 100% rename from starter/cloudrun/.eslint.tsconfig.json rename to starter/_base/.eslint.tsconfig.json diff --git a/starter/cloudrun/.eslintrc.cjs b/starter/_base/.eslintrc.cjs similarity index 74% rename from starter/cloudrun/.eslintrc.cjs rename to starter/_base/.eslintrc.cjs index 5ce82e8..6bd9011 100644 --- a/starter/cloudrun/.eslintrc.cjs +++ b/starter/_base/.eslintrc.cjs @@ -1,8 +1,9 @@ + module.exports = { ...require('@ackee/styleguide-backend-config/eslint'), root: true, - ignorePatterns: ['dist', 'src/openapi', 'docs'], + ignorePatterns: ['dist', 'docs', 'knexfile.ts'], parserOptions: { project: '.eslint.tsconfig.json', }, -} +} \ No newline at end of file diff --git a/starter/shared/.gitignore_ b/starter/_base/.gitignore similarity index 100% rename from starter/shared/.gitignore_ rename to starter/_base/.gitignore diff --git a/starter/shared/.mocha-junit-config.json b/starter/_base/.mocha-junit-config.json similarity index 100% rename from starter/shared/.mocha-junit-config.json rename to starter/_base/.mocha-junit-config.json diff --git a/starter/shared/.mocharc.json b/starter/_base/.mocharc.json similarity index 100% rename from starter/shared/.mocharc.json rename to starter/_base/.mocharc.json diff --git a/starter/shared/.nvmrc b/starter/_base/.nvmrc similarity index 100% rename from starter/shared/.nvmrc rename to starter/_base/.nvmrc diff --git a/starter/shared/Dockerfile b/starter/_base/Dockerfile similarity index 100% rename from starter/shared/Dockerfile rename to starter/_base/Dockerfile diff --git a/starter/_base/README.md b/starter/_base/README.md new file mode 100644 index 0000000..00fe1d4 --- /dev/null +++ b/starter/_base/README.md @@ -0,0 +1,53 @@ +# Create-Node-App Project + +Node.js application bootstrapped with [create-node-app](https://github.com/AckeeCZ/create-node-app) + +## 🏗️ Architecture + +All domain logic should live inside the [domain folder](src/domain) and should be accessed only via [container](src/container.ts). Each external dependency should be referenced by its own port inside the [domain/port](src/domain/ports) folder. These ports are also part of the container and can be implemented by any external dependency inside the [adapters](src/adapters/) folder. + +The application should be accessed through the [view](src/view/) layer of the application. All UI and interfaces should be defined there. The main entrypoint is defined in the [index.ts](src/index.ts) file. + +Each domain service should always accept [RequestContext](src/context.ts) as the first parameter. Part of the context is also the container with all of the application dependencies. + +## 👷 Development + +Application configuration is handled by [Configuru](https://github.com/AckeeCZ/configuru). All env options that can be changed or need to be set up are described in [.env.jsonc](.env.jsonc). + +The whole codebase is checked and improved using lint and prettier, run `lint:fix` and `prettier:fix` before committing changes to git. + +```bash +npm run lint:fix +npm run prettier:fix +``` + +## ✅ Tests + +Test are written using [mocha](https://github.com/mochajs/mocha). They are maintained in two ways: + +- **unit tests** should be next to the tested file with `test.ts` suffix, +- **integration tests** should be located inside the [test](src/test/) folder. + +Use mocked container during integration tests. + +If you need any prerequisites during tests, use the [setup.ts](src/test/setup.ts) file. + +To run tests use the test command: + +```bash +npm run test +``` + +## 🚀 Quick start + +1. Build the code + +```bash +npm run build +``` + +2. Start the entrypoint / server + +```bash +npm run start +``` diff --git a/starter/_base/package.json b/starter/_base/package.json new file mode 100644 index 0000000..93b98d3 --- /dev/null +++ b/starter/_base/package.json @@ -0,0 +1,45 @@ +{ + "name": "app", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "mocha", + "build": "tsc", + "start": "node -r source-map-support/register dist/index.js", + "ci-test:no-coverage": "npm run test -- --parallel=false -R mocha-multi-reporters --reporter-options configFile=.mocha-junit-config.json", + "ci-test": "nyc -a -r cobertura --report-dir output npm run ci-test:no-coverage", + "prettier": "prettier --check --write '**/*.{ts,js,json,jsonc,md}'", + "lint": "eslint '**/*.ts' -f codeframe --fix", + "codestyle": "npm run lint && npm run prettier", + "ci-lint": "npm run lint -- -f checkstyle -o ./output/checkstyle-result.xml", + "cli": "tsx ./src/view/cli/cli.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "configuru": "^1.0.0", + "pino": "^9.0.0", + "source-map-support": "^0.5.0" + }, + "devDependencies": { + "@ackee/styleguide-backend-config": "^1.0.1", + "@istanbuljs/nyc-config-typescript": "^1.0.0", + "@types/mocha": "^10.0.0", + "@types/node": "^24.0.0", + "eslint": "^8.0.0", + "eslint-formatter-gitlab": "^5.0.0", + "mocha": "^11.0.0", + "mocha-junit-reporter": "^2.0.0", + "mocha-multi-reporters": "^1.0.0", + "nyc": "^17.0.0", + "pino-pretty": "^13.0.0", + "prettier": "^3.0.0", + "ts-node": "^10.0.0", + "tsx": "^4.0.0", + "typescript": "^5.0.0", + "yargs": "^18.0.0" + }, + "type": "module" +} diff --git a/starter/shared/prettier.config.cjs b/starter/_base/prettier.config.cjs similarity index 100% rename from starter/shared/prettier.config.cjs rename to starter/_base/prettier.config.cjs diff --git a/starter/cloudrun/src/adapters/pino.logger.ts b/starter/_base/src/adapters/pino.logger.ts similarity index 96% rename from starter/cloudrun/src/adapters/pino.logger.ts rename to starter/_base/src/adapters/pino.logger.ts index a4ddbe1..55d28f8 100644 --- a/starter/cloudrun/src/adapters/pino.logger.ts +++ b/starter/_base/src/adapters/pino.logger.ts @@ -1,4 +1,4 @@ -import { pino as pinoLogger } from 'pino' +import pinoLogger from 'pino' import { LoggerFactoryPort } from '../domain/ports/logger.d.js' // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity diff --git a/starter/_base/src/config.ts b/starter/_base/src/config.ts new file mode 100644 index 0000000..2b3df52 --- /dev/null +++ b/starter/_base/src/config.ts @@ -0,0 +1,16 @@ +import { createLoader, maskedValues, values } from 'configuru' +import { Level } from 'pino' + +const loader = createLoader({ + defaultConfigPath: '.env.jsonc', +}) + +const configSchema = { + logger: { + defaultLevel: loader.custom(x => x as Level)('LOGGER_DEFAULT_LEVEL'), + pretty: loader.bool('LOGGER_PRETTY'), + }, +} + +export const config = values(configSchema) +export const safeConfig = maskedValues(configSchema) diff --git a/starter/cloudrun-graphql/src/container.ts b/starter/_base/src/container.ts similarity index 71% rename from starter/cloudrun-graphql/src/container.ts rename to starter/_base/src/container.ts index 8a46ab7..f7868c3 100644 --- a/starter/cloudrun-graphql/src/container.ts +++ b/starter/_base/src/container.ts @@ -6,7 +6,9 @@ export interface Container { logger: LoggerPort } -export const createContainer = (): Container => { +export type ContainerFactory = () => Promise + +export const createContainer: ContainerFactory = async () => { const logger = pinoLoggerFactory.create(config.logger) return { diff --git a/starter/cloudrun-graphql/src/context.ts b/starter/_base/src/context.ts similarity index 100% rename from starter/cloudrun-graphql/src/context.ts rename to starter/_base/src/context.ts diff --git a/starter/cloudrun-graphql/src/domain/errors/codes.ts b/starter/_base/src/domain/errors/codes.ts similarity index 100% rename from starter/cloudrun-graphql/src/domain/errors/codes.ts rename to starter/_base/src/domain/errors/codes.ts diff --git a/starter/cloudrun-graphql/src/domain/errors/errors.ts b/starter/_base/src/domain/errors/errors.ts similarity index 100% rename from starter/cloudrun-graphql/src/domain/errors/errors.ts rename to starter/_base/src/domain/errors/errors.ts diff --git a/starter/cloudrun-graphql/src/domain/ports/logger.d.ts b/starter/_base/src/domain/ports/logger.d.ts similarity index 100% rename from starter/cloudrun-graphql/src/domain/ports/logger.d.ts rename to starter/_base/src/domain/ports/logger.d.ts diff --git a/starter/_base/src/index.ts b/starter/_base/src/index.ts new file mode 100644 index 0000000..1480d81 --- /dev/null +++ b/starter/_base/src/index.ts @@ -0,0 +1,14 @@ +import { createContainer } from './container.js' +import { RequestContext } from './context.js' + +const entrypoint = async () => { + const ctx: RequestContext = { + container: await createContainer(), + type: 'api-user', + user: null, + } + + ctx.container.logger.info('Hello World! 🎉') +} + +void entrypoint() diff --git a/starter/shared/src/test/setup.ts b/starter/_base/src/test/setup.ts similarity index 100% rename from starter/shared/src/test/setup.ts rename to starter/_base/src/test/setup.ts diff --git a/starter/cloudrun/src/view/cli/README.md b/starter/_base/src/view/cli/README.md similarity index 62% rename from starter/cloudrun/src/view/cli/README.md rename to starter/_base/src/view/cli/README.md index 16495c1..dc5c363 100644 --- a/starter/cloudrun/src/view/cli/README.md +++ b/starter/_base/src/view/cli/README.md @@ -4,13 +4,9 @@ Cli tool to operate scripts that can use internal services or to add development ## 👷 Development -The CLI tool is build around `yargs` library. Each command needs its own `ts` file in current folder or in subfolder. The entrypoint `Cli.ts` scans the sub folders for `ts` files and intrerprets them as a command under the module called same as the folder. +The CLI tool is build around `yargs` library. Each command needs its own `ts` file in current folder or in subfolder. The entrypoint `Cli.ts` scans the sub folders for `ts` files and intrerprets them as a command under the module called same as the folder. Each command should export only functions and variables according to `CommandDefinition` in [cli.ts file](./cli.ts). -For example, current [openapi folder](./openapi) creates a new module `openapi` and assigns a new command called `generate` based on contents in [generate.ts](./openapi/generate.ts) file. - -Each command should export only functions and variables according to `CommandDefinition` in [cli.ts file](./cli.ts). - -Take a look at the [generate.ts](./openapi/generate.ts) for example how to implement own command. +For example, if you add `openapi` folder, it will creates a new module `openapi`. If you add a new command called `generate.ts`, it will also assign a new generate command to this module. ## ⚠️ Usage in production scripts diff --git a/starter/cloudrun/src/view/cli/cli.ts b/starter/_base/src/view/cli/cli.ts similarity index 100% rename from starter/cloudrun/src/view/cli/cli.ts rename to starter/_base/src/view/cli/cli.ts diff --git a/starter/shared/tsconfig.json b/starter/_base/tsconfig.json similarity index 100% rename from starter/shared/tsconfig.json rename to starter/_base/tsconfig.json diff --git a/starter/api/graphql/.env.jsonc b/starter/api/graphql/.env.jsonc new file mode 100644 index 0000000..f4d4de8 --- /dev/null +++ b/starter/api/graphql/.env.jsonc @@ -0,0 +1,8 @@ +{ + // Server will run on this port + "SERVER_PORT": 3000, + // Response development errors for debugging + "SERVER_ALLOW_RESPONSE_ERRORS": false, + // Enable GraphQL introspection + "SERVER_ENABLE_INTROSPECTION": true +} diff --git a/starter/cloudrun-graphql/.eslint.tsconfig.json b/starter/api/graphql/.eslint.tsconfig.json similarity index 100% rename from starter/cloudrun-graphql/.eslint.tsconfig.json rename to starter/api/graphql/.eslint.tsconfig.json diff --git a/starter/cloudrun-graphql/.eslintrc.cjs b/starter/api/graphql/.eslintrc.cjs similarity index 80% rename from starter/cloudrun-graphql/.eslintrc.cjs rename to starter/api/graphql/.eslintrc.cjs index cb60eb7..e2e6f9b 100644 --- a/starter/cloudrun-graphql/.eslintrc.cjs +++ b/starter/api/graphql/.eslintrc.cjs @@ -5,7 +5,7 @@ const defaultConfig = { module.exports = { root: true, - ignorePatterns: ['dist', 'docs', 'src/generated'], + ignorePatterns: ['dist', 'src/openapi', 'docs', 'knexfile.ts'], overrides: [ { ...omit(defaultConfig, ['ignorePatterns']), @@ -14,10 +14,9 @@ module.exports = { project: '.eslint.tsconfig.json', }, rules: { - ...defaultConfig['rules'], - '@typescript-eslint/strict-boolean-expressions': 0, - '@typescript-eslint/no-misused-promises': 'warn', - }, + ...defaultConfig.rules, + '@typescript-eslint/no-empty-object-type': 0, + } }, { files: ['**/*.graphql'], diff --git a/starter/cloudrun-graphql/codegen.yml b/starter/api/graphql/codegen.yml similarity index 100% rename from starter/cloudrun-graphql/codegen.yml rename to starter/api/graphql/codegen.yml diff --git a/starter/api/graphql/node-app.jsonc b/starter/api/graphql/node-app.jsonc new file mode 100644 index 0000000..52a7d12 --- /dev/null +++ b/starter/api/graphql/node-app.jsonc @@ -0,0 +1,6 @@ +{ + "module": "API", + "id": "graphql", + "name": "GraphQL", + "prebuild": ["generate:api"] +} diff --git a/starter/api/graphql/package.json b/starter/api/graphql/package.json new file mode 100644 index 0000000..fa92484 --- /dev/null +++ b/starter/api/graphql/package.json @@ -0,0 +1,36 @@ +{ + "name": "app-api-graphql", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "generate:api": "graphql-codegen --config codegen.yml && npm run codestyle", + "build:copy-schema": "mkdir -p ./dist/view/graphql/schema && cp -r ./src/view/graphql/schema ./dist/view/graphql/schema", + "build": "npm run build:copy-schema && tsc" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@as-integrations/express5": "^1.1.2", + "@apollo/server": "^4.1.0", + "@graphql-tools/load-files": "^7.0.0", + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/schema": "^10.0.0", + "lodash-es": "^4.17.21", + "express": "^5.0.0", + "graphql": "^16.0.0", + "node-healthz": "^2.0.0", + "pino-http": "^10.0.0" + }, + "devDependencies": { + "@graphql-codegen/cli": "^5.0.0", + "@graphql-codegen/typescript": "^4.0.0", + "@graphql-codegen/typescript-resolvers": "^4.0.0", + "@graphql-eslint/eslint-plugin": "^4.4.0", + "@types/express": "^5.0.0", + "@types/supertest": "^6.0.0", + "supertest": "^7.0.0" + }, + "type": "module" +} diff --git a/starter/cloudrun-graphql/src/config.ts b/starter/api/graphql/src/config.ts similarity index 77% rename from starter/cloudrun-graphql/src/config.ts rename to starter/api/graphql/src/config.ts index 2892ea0..25abbea 100644 --- a/starter/cloudrun-graphql/src/config.ts +++ b/starter/api/graphql/src/config.ts @@ -11,10 +11,6 @@ const configSchema = { allowResponseErrors: loader.bool('SERVER_ALLOW_RESPONSE_ERRORS'), enableIntrospection: loader.bool('SERVER_ENABLE_INTROSPECTION'), }, - logger: { - defaultLevel: loader.custom(x => x as any as Level)('LOGGER_DEFAULT_LEVEL'), - pretty: loader.bool('LOGGER_PRETTY'), - }, } export const config = values(configSchema) diff --git a/starter/api/graphql/src/index.ts b/starter/api/graphql/src/index.ts new file mode 100644 index 0000000..e6f8416 --- /dev/null +++ b/starter/api/graphql/src/index.ts @@ -0,0 +1,11 @@ +import { config, safeConfig } from './config.js' +import { createAppServer, startServer } from './view/server.js' +import { pinoLoggerFactory } from './adapters/pino.logger.js' +import { createContainer } from './container.js' + +const logger = pinoLoggerFactory.create(config.logger) + +logger.info({ config: safeConfig }, 'Loaded config') + +const appServer = createAppServer() +void startServer({ ...appServer, logger, containerFactory: createContainer }) diff --git a/starter/cloudrun-graphql/src/test/helloWorld.test.ts b/starter/api/graphql/src/test/helloWorld.test.ts similarity index 60% rename from starter/cloudrun-graphql/src/test/helloWorld.test.ts rename to starter/api/graphql/src/test/helloWorld.test.ts index 68beb79..04ca464 100644 --- a/starter/cloudrun-graphql/src/test/helloWorld.test.ts +++ b/starter/api/graphql/src/test/helloWorld.test.ts @@ -1,16 +1,27 @@ import assert from 'node:assert' -import { describe, it } from 'mocha' +import { describe, before, test } from 'mocha' import { createAppServer } from '../view/server.js' import { gql } from 'graphql-tag' +import { ApolloServer } from '@apollo/server' describe('Hello world', () => { - it('should return greeting', async () => { + let server: ApolloServer + + before(async () => { + const { server: appServer } = createAppServer() + server = appServer + }) + + after(async () => { + await server.stop() + }) + + test('should return greeting', async () => { const query = gql` query Hello { greeting } ` - const { server } = createAppServer() const res = await server.executeOperation({ query }) assert(res.body.kind === 'single') diff --git a/starter/cloudrun-graphql/src/view/controller.ts b/starter/api/graphql/src/view/controller.ts similarity index 100% rename from starter/cloudrun-graphql/src/view/controller.ts rename to starter/api/graphql/src/view/controller.ts diff --git a/starter/api/graphql/src/view/graphql/context-factory.ts b/starter/api/graphql/src/view/graphql/context-factory.ts new file mode 100644 index 0000000..b0fe7e4 --- /dev/null +++ b/starter/api/graphql/src/view/graphql/context-factory.ts @@ -0,0 +1,13 @@ +import { RequestContext } from '../../context.js' +import { ContainerFactory } from '../../container.js' + +export const contextFactory = async ( + containerFactory: ContainerFactory +): Promise => { + const container = await containerFactory() + return { + type: 'api-user', + container, + user: null, // Add UserContext if Auth is implemented + } +} diff --git a/starter/cloudrun-graphql/src/view/graphql/resolvers.ts b/starter/api/graphql/src/view/graphql/resolvers.ts similarity index 100% rename from starter/cloudrun-graphql/src/view/graphql/resolvers.ts rename to starter/api/graphql/src/view/graphql/resolvers.ts diff --git a/starter/cloudrun-graphql/src/view/graphql/resolvers/greeting.resolver.ts b/starter/api/graphql/src/view/graphql/resolvers/greeting.resolver.ts similarity index 100% rename from starter/cloudrun-graphql/src/view/graphql/resolvers/greeting.resolver.ts rename to starter/api/graphql/src/view/graphql/resolvers/greeting.resolver.ts diff --git a/starter/cloudrun-graphql/src/view/graphql/schema.ts b/starter/api/graphql/src/view/graphql/schema.ts similarity index 100% rename from starter/cloudrun-graphql/src/view/graphql/schema.ts rename to starter/api/graphql/src/view/graphql/schema.ts diff --git a/starter/cloudrun-graphql/src/view/graphql/schema/schema.graphql b/starter/api/graphql/src/view/graphql/schema/schema.graphql similarity index 100% rename from starter/cloudrun-graphql/src/view/graphql/schema/schema.graphql rename to starter/api/graphql/src/view/graphql/schema/schema.graphql diff --git a/starter/cloudrun-graphql/src/view/server.ts b/starter/api/graphql/src/view/server.ts similarity index 69% rename from starter/cloudrun-graphql/src/view/server.ts rename to starter/api/graphql/src/view/server.ts index 4b532b9..7433723 100644 --- a/starter/cloudrun-graphql/src/view/server.ts +++ b/starter/api/graphql/src/view/server.ts @@ -6,7 +6,9 @@ import { schema } from './graphql/schema.js' import express from 'express' import { ctrl } from './controller.js' import { expressMiddleware } from '@as-integrations/express5' -import { Container } from '../container.js' +import { LoggerPort } from '../domain/ports/logger.d.js' +import { ContainerFactory } from '../container.js' +import { contextFactory } from './graphql/context-factory.js' export const clientSchema = makeExecutableSchema({ typeDefs: schema, @@ -29,13 +31,21 @@ export const createAppServer = () => { export async function startServer({ app, server, - container, -}: ReturnType & { container: Container }) { - const { logger } = container - + logger, + containerFactory, +}: ReturnType & { + logger: LoggerPort + containerFactory: ContainerFactory +}) { await server.start() - app.use('/api/graphql', ctrl.json, expressMiddleware(server)) + app.use( + '/api/graphql', + ctrl.json, + expressMiddleware(server, { + context: () => contextFactory(containerFactory), + }) + ) app.listen({ port: config.server.port }, () => logger.info({}, `Server started, port=${config.server.port}`) diff --git a/starter/api/rest/.env.jsonc b/starter/api/rest/.env.jsonc new file mode 100644 index 0000000..ec0b4a3 --- /dev/null +++ b/starter/api/rest/.env.jsonc @@ -0,0 +1,6 @@ +{ + // API server listening port. + "SERVER_PORT": 3000, + // Boolean to remove sensitive info from http error responses + "ENABLE_PRODUCTION_HTTP_ERROR_RESPONSES": false +} diff --git a/starter/api/rest/.eslintrc.cjs b/starter/api/rest/.eslintrc.cjs new file mode 100644 index 0000000..da2d49f --- /dev/null +++ b/starter/api/rest/.eslintrc.cjs @@ -0,0 +1,8 @@ +module.exports = { + ...require('@ackee/styleguide-backend-config/eslint'), + root: true, + ignorePatterns: ['dist', 'src/openapi', 'docs', 'knexfile.ts'], + parserOptions: { + project: '.eslint.tsconfig.json', + }, +} diff --git a/starter/api/rest/node-app.jsonc b/starter/api/rest/node-app.jsonc new file mode 100644 index 0000000..64cacc8 --- /dev/null +++ b/starter/api/rest/node-app.jsonc @@ -0,0 +1,6 @@ +{ + "module": "API", + "id": "rest", + "name": "RESTful", + "prebuild": ["generate:api"] +} diff --git a/starter/api/rest/package.json b/starter/api/rest/package.json new file mode 100644 index 0000000..7c45b07 --- /dev/null +++ b/starter/api/rest/package.json @@ -0,0 +1,25 @@ +{ + "name": "app-api-rest", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "generate:api": "npm run cli openapi generate src/view/rest/spec/openapi.yml && npm run codestyle" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^5.0.0", + "node-healthz": "^2.0.0", + "pino-http": "^10.0.0" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/supertest": "^6.0.0", + "openapi-typescript": "^7.0.0", + "supertest": "^7.0.0", + "yaml": "^2.0.0" + }, + "type": "module" +} diff --git a/starter/cloudrun/src/config.ts b/starter/api/rest/src/config.ts similarity index 72% rename from starter/cloudrun/src/config.ts rename to starter/api/rest/src/config.ts index f650f88..cea6879 100644 --- a/starter/cloudrun/src/config.ts +++ b/starter/api/rest/src/config.ts @@ -1,15 +1,10 @@ import { createLoader, maskedValues, values } from 'configuru' -import { Level } from 'pino' const loader = createLoader({ defaultConfigPath: '.env.jsonc', }) const configSchema = { - logger: { - defaultLevel: loader.custom(x => x as Level)('LOGGER_DEFAULT_LEVEL'), - pretty: loader.bool('LOGGER_PRETTY'), - }, server: { port: loader.number('SERVER_PORT'), enableProductionHttpErrorResponses: loader.bool( diff --git a/starter/api/rest/src/container.ts b/starter/api/rest/src/container.ts new file mode 100644 index 0000000..ce48ceb --- /dev/null +++ b/starter/api/rest/src/container.ts @@ -0,0 +1,13 @@ +import { healthCheckService } from './domain/health-check.service.js' + +export interface Container { + healthCheckService: typeof healthCheckService +} + +export type ContainerFactory = () => Promise + +export const createContainer: ContainerFactory = async () => { + return { + healthCheckService, + } +} diff --git a/starter/cloudrun/src/domain/health-check.service.ts b/starter/api/rest/src/domain/health-check.service.ts similarity index 100% rename from starter/cloudrun/src/domain/health-check.service.ts rename to starter/api/rest/src/domain/health-check.service.ts diff --git a/starter/cloudrun/src/index.ts b/starter/api/rest/src/index.ts similarity index 65% rename from starter/cloudrun/src/index.ts rename to starter/api/rest/src/index.ts index a1d9515..44fdd5a 100644 --- a/starter/cloudrun/src/index.ts +++ b/starter/api/rest/src/index.ts @@ -1,11 +1,11 @@ import { config } from './config.js' -import { createContainer } from './container.js' import { createServer } from './view/server.js' +import { pinoLoggerFactory } from './adapters/pino.logger.js' +import { createContainer } from './container.js' -const appContainer = createContainer() -const { logger } = appContainer +const logger = pinoLoggerFactory.create(config.logger) -const server = createServer(appContainer) +const server = await createServer(createContainer) server.listen(config.server.port, () => { logger.info( diff --git a/starter/cloudrun/src/test/health-check.test.ts b/starter/api/rest/src/test/health-check.test.ts similarity index 76% rename from starter/cloudrun/src/test/health-check.test.ts rename to starter/api/rest/src/test/health-check.test.ts index c8d7288..3c5dd5f 100644 --- a/starter/cloudrun/src/test/health-check.test.ts +++ b/starter/api/rest/src/test/health-check.test.ts @@ -5,12 +5,10 @@ import { createContainer } from '../container.js' import { requestTyped } from './util/openapi-test.util.js' describe('Health Check API', () => { - let server: ReturnType - let container: ReturnType + let server: Awaited> - before(() => { - container = createContainer() - server = createServer(container) + before(async () => { + server = await createServer(createContainer) }) describe('GET /api/v1/healthz', () => { diff --git a/starter/cloudrun/src/test/util/openapi-test.util.ts b/starter/api/rest/src/test/util/openapi-test.util.ts similarity index 94% rename from starter/cloudrun/src/test/util/openapi-test.util.ts rename to starter/api/rest/src/test/util/openapi-test.util.ts index 9546da9..f9d5f25 100644 --- a/starter/cloudrun/src/test/util/openapi-test.util.ts +++ b/starter/api/rest/src/test/util/openapi-test.util.ts @@ -21,7 +21,7 @@ export const requestTyped = < Resource extends KeysOfUnion, Method extends Exclude, 'parameters'>, Resp extends OpenApiRouteResponseBody, - Openapi extends openapi.paths = openapi.paths + Openapi extends openapi.paths = openapi.paths, >( server: Express, resource: Resource, @@ -57,10 +57,10 @@ export const requestTyped = < ) { if (headers) { Object.entries(headers).forEach(([key, value]) => { - void req.set(key, value) + req.set(key, value) }) } - void originalSend(body as any) + originalSend(body as any) return enhanced }, responseTyped: () => { diff --git a/starter/cloudrun/src/view/cli/openapi/generate.ts b/starter/api/rest/src/view/cli/openapi/generate.ts similarity index 100% rename from starter/cloudrun/src/view/cli/openapi/generate.ts rename to starter/api/rest/src/view/cli/openapi/generate.ts diff --git a/starter/cloudrun/src/view/rest/controller/health-check.controller.ts b/starter/api/rest/src/view/rest/controllers/health-check.controller.ts similarity index 100% rename from starter/cloudrun/src/view/rest/controller/health-check.controller.ts rename to starter/api/rest/src/view/rest/controllers/health-check.controller.ts diff --git a/starter/cloudrun/src/view/rest/middleware/context-middleware.ts b/starter/api/rest/src/view/rest/middleware/context-middleware.ts similarity index 100% rename from starter/cloudrun/src/view/rest/middleware/context-middleware.ts rename to starter/api/rest/src/view/rest/middleware/context-middleware.ts diff --git a/starter/cloudrun/src/view/rest/middleware/error-handler.ts b/starter/api/rest/src/view/rest/middleware/error-handler.ts similarity index 95% rename from starter/cloudrun/src/view/rest/middleware/error-handler.ts rename to starter/api/rest/src/view/rest/middleware/error-handler.ts index 44411e3..9a7c955 100644 --- a/starter/cloudrun/src/view/rest/middleware/error-handler.ts +++ b/starter/api/rest/src/view/rest/middleware/error-handler.ts @@ -42,7 +42,7 @@ export function createErrorHandler( return (error, _req, res, _next) => { const statusCode = error instanceof DomainError - ? ERROR_DOMAIN_CODE_TO_HTTP_STATUS[error.code] ?? 500 + ? (ERROR_DOMAIN_CODE_TO_HTTP_STATUS[error.code] ?? 500) : 500 ;(res as any).error = errorToDevObject(error) diff --git a/starter/cloudrun/src/view/rest/middleware/request-logger.ts b/starter/api/rest/src/view/rest/middleware/request-logger.ts similarity index 100% rename from starter/cloudrun/src/view/rest/middleware/request-logger.ts rename to starter/api/rest/src/view/rest/middleware/request-logger.ts diff --git a/starter/cloudrun/src/view/rest/request.d.ts b/starter/api/rest/src/view/rest/request.d.ts similarity index 100% rename from starter/cloudrun/src/view/rest/request.d.ts rename to starter/api/rest/src/view/rest/request.d.ts diff --git a/starter/cloudrun/src/view/rest/routes.ts b/starter/api/rest/src/view/rest/routes.ts similarity index 79% rename from starter/cloudrun/src/view/rest/routes.ts rename to starter/api/rest/src/view/rest/routes.ts index d54c3f8..a1a88b4 100644 --- a/starter/cloudrun/src/view/rest/routes.ts +++ b/starter/api/rest/src/view/rest/routes.ts @@ -1,6 +1,6 @@ import express from 'express' import { openApiRouter, registerOpenApiRoutes } from './util/openapi.util.js' -import { healthCheckController } from './controller/health-check.controller.js' +import { healthCheckController } from './controllers/health-check.controller.js' const apiRouter = openApiRouter(express.Router(), { removePrefix: '/api/v1', diff --git a/starter/cloudrun/src/view/rest/spec/openapi.yml b/starter/api/rest/src/view/rest/spec/openapi.yml similarity index 100% rename from starter/cloudrun/src/view/rest/spec/openapi.yml rename to starter/api/rest/src/view/rest/spec/openapi.yml diff --git a/starter/cloudrun/src/view/rest/util/openapi.util.ts b/starter/api/rest/src/view/rest/util/openapi.util.ts similarity index 93% rename from starter/cloudrun/src/view/rest/util/openapi.util.ts rename to starter/api/rest/src/view/rest/util/openapi.util.ts index 6be3436..f8efc7e 100644 --- a/starter/cloudrun/src/view/rest/util/openapi.util.ts +++ b/starter/api/rest/src/view/rest/util/openapi.util.ts @@ -6,7 +6,7 @@ import { RequestContext } from '../../../context.js' export type OpenApiRouteResponseBodyMethod< T, TMethod extends string = 'get', - TDefault = unknown + TDefault = unknown, > = T extends { [key in TMethod]: { responses: { 200: { content: { 'application/json': infer U } } } @@ -17,7 +17,7 @@ export type OpenApiRouteResponseBodyMethod< export type OpenApiRouteResponseBody< T, - TMethod extends string = 'get' + TMethod extends string = 'get', > = OpenApiRouteResponseBodyMethod< T, TMethod, @@ -41,18 +41,18 @@ export type OpenApiRoutePathParam = T extends { } ? U : T extends { post: { parameters: { path: infer U } } } - ? U - : T extends { put: { parameters: { path: infer U } } } - ? U - : unknown + ? U + : T extends { put: { parameters: { path: infer U } } } + ? U + : unknown export type OpenApiRouteQueryParam = T extends { get: { parameters: { query: infer U } } } ? U : T extends { post: { parameters: { query: infer U } } } - ? U - : unknown + ? U + : unknown export type OpenApiRouteHeaderParam = T extends { get: { @@ -63,14 +63,14 @@ export type OpenApiRouteHeaderParam = T extends { } ? LowercaseKeys : T extends { - post: { - parameters: { - header: infer U extends Record + post: { + parameters: { + header: infer U extends Record + } } } - } - ? LowercaseKeys - : unknown + ? LowercaseKeys + : unknown export type OpenApiRouteParam = OpenApiRoutePathParam & OpenApiRouteQueryParam & @@ -79,7 +79,7 @@ export type OpenApiRouteParam = OpenApiRoutePathParam & export type OpenApiRouteRequestBodyMethod< T, TMethod extends string = 'post', - TDefault = unknown + TDefault = unknown, > = T extends { [key in TMethod]: { requestBody: { @@ -94,7 +94,7 @@ export type OpenApiRouteRequestBodyMethod< export type OpenApiRouteRequestBody< T, - TMethod extends string = 'post' + TMethod extends string = 'post', > = OpenApiRouteRequestBodyMethod< T, TMethod, @@ -150,7 +150,7 @@ type MimeContent = { type MimeContentValue< MimeType extends ApiMimeTypes, - T extends MimeContent + T extends MimeContent, > = { [K in keyof T['content']]: T['content'][K] }[keyof T['content']] @@ -194,7 +194,7 @@ type RouteHandlers = { } export type RestApiController< - SubsetOperationIds extends OperationIds = OperationIds + SubsetOperationIds extends OperationIds = OperationIds, > = { [Key in SubsetOperationIds]: OpenApiHandler } @@ -225,7 +225,7 @@ export const openApiRouter = ( route: < Method extends keyof paths[Path], Path extends keyof paths, - OperationId extends OperationIds + OperationId extends OperationIds, >( method: Method, path: Path, diff --git a/starter/cloudrun/src/view/server.ts b/starter/api/rest/src/view/server.ts similarity index 71% rename from starter/cloudrun/src/view/server.ts rename to starter/api/rest/src/view/server.ts index 29bb2b6..7ab9540 100644 --- a/starter/cloudrun/src/view/server.ts +++ b/starter/api/rest/src/view/server.ts @@ -1,18 +1,20 @@ import express from 'express' import { createRequestLogger } from './rest/middleware/request-logger.js' -import { Container } from '../container.js' import { config } from '../config.js' import { createErrorHandler } from './rest/middleware/error-handler.js' import { routes } from './rest/routes.js' import { createContextMiddleware } from './rest/middleware/context-middleware.js' +import { ContainerFactory } from '../container.js' -export const createServer = (appContainer: Container) => { - const { logger } = appContainer +export const createServer = async (containerFactory: ContainerFactory) => { + const container = await containerFactory() + const { logger } = container const server = express() + const errorHandler = createErrorHandler(config.server) const requestLogger = createRequestLogger(logger) - const contextMiddleware = createContextMiddleware(appContainer) + const contextMiddleware = createContextMiddleware(container) server.disable('x-powered-by') diff --git a/starter/cloudrun-graphql/.env.jsonc b/starter/cloudrun-graphql/.env.jsonc deleted file mode 100644 index 84b52f8..0000000 --- a/starter/cloudrun-graphql/.env.jsonc +++ /dev/null @@ -1,12 +0,0 @@ -{ - // Server will run on this port - "SERVER_PORT": 3000, - // Logging level, see https://github.com/pinojs/pino/blob/master/docs/api.md#logger-level - "LOGGER_DEFAULT_LEVEL": "debug", - // Enable/disable logging object multiline formatted logging https://github.com/pinojs/pino/blob/master/docs/api.md#prettyprint-boolean--object - "LOGGER_PRETTY": false, - // Response development errors for debugging - "SERVER_ALLOW_RESPONSE_ERRORS": false, - // Enable GraphQL introspection - "SERVER_ENABLE_INTROSPECTION": true -} diff --git a/starter/cloudrun-graphql/README.md b/starter/cloudrun-graphql/README.md deleted file mode 100644 index 70852f4..0000000 --- a/starter/cloudrun-graphql/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# GraphQL Cloudrun Starter - -Node.js project scaffolded with Cloudrun and GraphQL - -## 🎉 Initialize project - -Run `create-node-app cloudrun-graphql` to init your project. By default project is created in `../node-app` folder. - -You can pass `destination` argument into the command as well. -Example: - -- `create-node-app cloudrun-graphql /Users/foo/Documents/bar ` - -## 👷 Continuous Integration - -### Environment variables - -Make sure you replace all the variable values containing `REPLACEME` in `ci-branch-config` files. - -The following variables must be set for each branch in `ci-branch-config` directory. - -- `GCP_PROJECT_ID` - GCP project identifier -- `ENVIRONMENT` - e.g. `development` - -Optional variables: - -- `ALLOCATED_MEMORY` - Memory allocated at Cloudrun, default is 384Mi -- `CLOUD_RUN_SERVICE_ACCOUNT` - CloudRun service account -- `ENV_SECRETS` - Secret variables of the deployment, format is: `KEY=[NAME OF SECRET IN SECRET MANAGER:VERSION],...` -- `ENV_VARS` - Environment variables of the deployment, format is: `KEY=VALUE,...` -- `GCP_SA_KEY` - We use different service accounts for different environments. So we have to overwrite `GCP_SA_KEY` variable e.g.`GCP_SA_KEY=$SECRET_GCP_SA_KEY_DEVELOPMENT` Variable `SECRET_GCP_SA_KEY_` should be set in `GitLab CI secret variables` -- `GCP_SECRET_NAME` - Name of secret in Google Secret Manager -- `MAX_INSTANCES` - Maximum instance count in Cloudrun, default is 8 -- `MIN_INSTANCES` - Minimum instance count in Cloudrun, default is 0 -- `SECRET_PATH` - CloudRun volume where secrets will be injected e.g. `/config/secrets.json` can't be the same path ass app work dir e.g. `/usr/src/app` deploy will fail cause secret protection. But have to be identical with ENV `CFG_JSON_PATH` in Dockerfile -- `SKIP_AUDIT` - Skip NPM Audit, defaults to `false` -- `SKIP_LINT` - Skip lint, defaults to `false` -- `SKIP_TESTS` - Skip tests, defaults to `false` -- `SQL_INSTANCE_NAME` - SQL instance name -- `VPC_CONNECTOR_NAME` - serverless connector name, has to be in the same region -- `DOCKER_REGISTRY_TYPE` - whenever to push Docker image into Container Registry or Artifacts Registry, default is - `container` -- `DOCKER_REGISTRY_URL` - hostname of Docker Registry, defaults to `eu.gcr.io` -- `ANY_ADDITIONAL_CLOUDRUN_ARGS` - any argument required by Cloud Run, eg `--concurrency=1000 --clear-labels ...` - -Common variables: - -- `GCP_TEST_SECRET_PROJECT_ID` - GCP project identifier for test secrets -- `GCP_SECRET_TEST_NAME` - Name of test secret in Google Secret Manager - -## 📄 Additional Resources - -- [Google Cloudrun docs](https://cloud.google.com/run/docs) diff --git a/starter/cloudrun-graphql/src/adapters/pino.logger.ts b/starter/cloudrun-graphql/src/adapters/pino.logger.ts deleted file mode 100644 index a4ddbe1..0000000 --- a/starter/cloudrun-graphql/src/adapters/pino.logger.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { pino as pinoLogger } from 'pino' -import { LoggerFactoryPort } from '../domain/ports/logger.d.js' - -// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity -const PinoLevelToSeverityLookup: Record = { - trace: 'DEBUG', - debug: 'DEBUG', - info: 'INFO', - warn: 'WARNING', - error: 'ERROR', - fatal: 'CRITICAL', -} as const - -const defaultPinoConf = (defaultLevel: string) => ({ - messageKey: 'message', - formatters: { - messageKey: 'message', - level: (label: string, num: number) => { - return { - severity: - PinoLevelToSeverityLookup[label] ?? - PinoLevelToSeverityLookup[defaultLevel], - level: num, - } - }, - }, -}) - -export const pinoLoggerFactory: LoggerFactoryPort = { - create: config => { - return pinoLogger({ - ...defaultPinoConf(config.defaultLevel), - transport: config.enablePrettyPrint - ? { - target: 'pino-pretty', - options: { - colorize: true, - }, - } - : undefined, - level: config.defaultLevel, - }) - }, -} diff --git a/starter/cloudrun-graphql/src/index.ts b/starter/cloudrun-graphql/src/index.ts deleted file mode 100644 index 9534d17..0000000 --- a/starter/cloudrun-graphql/src/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { safeConfig } from './config.js' -import { createAppServer, startServer } from './view/server.js' -import { createContainer } from './container.js' - -const appContainer = createContainer() -const { logger } = appContainer - -logger.info({ config: safeConfig }, 'Loaded config') - -const appServer = createAppServer() -void startServer({ ...appServer, container: appContainer }) diff --git a/starter/cloudrun/README.md b/starter/cloudrun/README.md deleted file mode 100644 index 9c4a4d9..0000000 --- a/starter/cloudrun/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Cloudrun Starter - -Node.js project scaffolded with create-node-app Cloudrun - -## 🎉 Initialize new project - -Run `create-node-app cloudrun` to init your project. By default project is created in `../node-app` folder. - -You can pass `destination` argument into the command as well. -Example: - -- `create-node-app cloudrun /Users/foo/Documents/bar` - -## 🧑‍💻 Development - -Project follows port-adapters folder structure. Three main layers can be found in [src folder](src): - -- [domain](src/domain) containing all domain services and ports for external services, -- [adapters](src/adapters) containing implementations of ports, -- and [view](src/view) containing entrypoints to the application (rest, cli). - -The main entrypoint of the application is defined in the [src/index.ts](index.ts) file. The applicaiton dependencies are defined -and maintained in the [container.ts](src/container.ts) file which loads configuration from [config.ts](src/config.ts) using [configuru library](https://github.com/AckeeCZ/configuru). - -Tests are divided in the two parts: - -- integration tests should be maintained in the [test folder](src/test/) -- unit tests should be kept close to the targeted file and hold the same name as the tested file but with `test.ts` suffix - -## 👷 Continuous Integration - -### Environment variables - -If you didn't provided GCloud project parameter, make sure you replace all the variable values containing `node-app` in `ci-branch-config` files. - -The following variables must be set for each branch in `ci-branch-config` directory. - -- `GCP_PROJECT_ID` - GCP project identifier -- `ENVIRONMENT` - e.g. `development` - -Optional variables: - -- `ALLOCATED_MEMORY` - Memory allocated at Cloudrun, default is 384Mi -- `CLOUD_RUN_SERVICE_ACCOUNT` - CloudRun service account -- `ENV_SECRETS` - Secret variables of the deployment, format is: `KEY=[NAME OF SECRET IN SECRET MANAGER:VERSION],...` -- `ENV_VARS` - Environment variables of the deployment, format is: `KEY=VALUE,...` -- `GCP_SA_KEY` - We use different service accounts for different environments. So we have to overwrite `GCP_SA_KEY` variable e.g.`GCP_SA_KEY=$SECRET_GCP_SA_KEY_DEVELOPMENT` Variable `SECRET_GCP_SA_KEY_` should be set in `GitLab CI secret variables` -- `GCP_SECRET_NAME` - Name of secret in Google Secret Manager -- `MAX_INSTANCES` - Maximum instance count in Cloudrun, default is 8 -- `MIN_INSTANCES` - Minimum instance count in Cloudrun, default is 0 -- `SECRET_PATH` - CloudRun volume where secrets will be injected e.g. `/config/secrets.json` can't be the same path ass app work dir e.g. `/usr/src/app` deploy will fail cause secret protection. But have to be identical with ENV `CFG_JSON_PATH` in Dockerfile -- `SKIP_AUDIT` - Skip NPM Audit, defaults to `false` -- `SKIP_LINT` - Skip lint, defaults to `false` -- `SKIP_TESTS` - Skip tests, defaults to `false` -- `SQL_INSTANCE_NAME` - SQL instance name -- `VPC_CONNECTOR_NAME` - serverless connector name, has to be in the same region -- `DOCKER_REGISTRY_TYPE` - whenever to push Docker image into Container Registry or Artifacts Registry, default is - `container` -- `DOCKER_REGISTRY_URL` - hostname of Docker Registry, defaults to `eu.gcr.io` -- `ANY_ADDITIONAL_CLOUDRUN_ARGS` - any argument required by Cloud Run, eg `--concurrency=1000 --clear-labels ...` - -Common variables: - -- `GCP_TEST_SECRET_PROJECT_ID` - GCP project identifier for test secrets -- `GCP_SECRET_TEST_NAME` - Name of test secret in Google Secret Manager - -## 📄 Additional Resources - -- [Google Cloudrun docs](https://cloud.google.com/run/docs) diff --git a/starter/cloudrun/src/container.ts b/starter/cloudrun/src/container.ts deleted file mode 100644 index 966eac6..0000000 --- a/starter/cloudrun/src/container.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { config } from './config.js' -import { pinoLoggerFactory } from './adapters/pino.logger.js' -import { LoggerPort } from './domain/ports/logger.d.js' -import { healthCheckService } from './domain/health-check.service.js' - -export interface Container { - logger: LoggerPort - healthCheckService: typeof healthCheckService -} - -export const createContainer = (): Container => { - const logger = pinoLoggerFactory.create(config.logger) - - return { - logger, - healthCheckService, - } -} diff --git a/starter/cloudrun/src/context.ts b/starter/cloudrun/src/context.ts deleted file mode 100644 index 1784f41..0000000 --- a/starter/cloudrun/src/context.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Container } from './container.js' - -interface BaseContext { - container: Container - note?: string -} - -export interface ApiUserRequestContext extends BaseContext { - type: 'api-user' - user: null // Add UserContext if Auth is implemented -} - -export interface ServerRequestContext extends BaseContext { - type: 'server' -} - -/** - * Defines context in which current application runs. - * Context should be created with every external call (user request, cli input, ...) - */ -export type RequestContext = ApiUserRequestContext | ServerRequestContext - -/** - * Creator of the context for the App. Every API layer is responsible for - * creating the context based on the Api parameters (http headers, protocol settings etc...) - */ -export type RequestContextFactory = ( - container: Readonly, - ...params: Params -) => Promise - -/** - * Creator of the server context that should be used only in executions that are invoked - * on server, f.e. CLI, server start up etc. - */ -export type ServerRequestContextFactory = ( - container: Readonly, - ...params: Params -) => Promise diff --git a/starter/cloudrun/src/domain/errors/codes.ts b/starter/cloudrun/src/domain/errors/codes.ts deleted file mode 100644 index c3eb641..0000000 --- a/starter/cloudrun/src/domain/errors/codes.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum ErrorCode { - UNKNOWN = 0, - VALIDATION = 1000, -} - -export const errorMessages = { - [ErrorCode.UNKNOWN]: 'Unknown error', - [ErrorCode.VALIDATION]: 'Validation error', -} diff --git a/starter/cloudrun/src/domain/errors/errors.ts b/starter/cloudrun/src/domain/errors/errors.ts deleted file mode 100644 index b722438..0000000 --- a/starter/cloudrun/src/domain/errors/errors.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ErrorCode, errorMessages } from './codes.js' - -export class DomainError extends Error { - constructor( - public readonly code: ErrorCode, - public readonly message: string = errorMessages[code], - public readonly data?: AdditionalData - ) { - super(message) - } -} - -export type ValidationErrorData = - | Array<{ field: string; message: string }> - | { field: string; message: string } - -export class ValidationError extends DomainError { - constructor(errors: ValidationErrorData) { - super( - ErrorCode.VALIDATION, - errorMessages[ErrorCode.VALIDATION], - Array.isArray(errors) ? errors : [errors] - ) - } -} diff --git a/starter/cloudrun/src/domain/ports/logger.d.ts b/starter/cloudrun/src/domain/ports/logger.d.ts deleted file mode 100644 index 5ec9a85..0000000 --- a/starter/cloudrun/src/domain/ports/logger.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -export interface LoggerConfig { - defaultLevel: string - enablePrettyPrint?: boolean -} - -type BaseLoggerFn = (object: any, message?: string) => void - -export interface LoggerPort { - level: string - debug: BaseLoggerFn - info: BaseLoggerFn - warn: BaseLoggerFn - error: BaseLoggerFn - fatal: BaseLoggerFn - trace: BaseLoggerFn - silent: BaseLoggerFn -} - -export interface LoggerFactoryPort { - create: (config: LoggerConfig) => LoggerPort -} diff --git a/starter/infra/postgresql-knex/.env.jsonc b/starter/infra/postgresql-knex/.env.jsonc new file mode 100644 index 0000000..99319ec --- /dev/null +++ b/starter/infra/postgresql-knex/.env.jsonc @@ -0,0 +1,5 @@ +{ + // DATABASE + /// Application PostgreSQL database connection props + "DB_CONNECTION_STRING": "postgres://{{PROJECT_NAME}}_docker:{{PROJECT_NAME}}_docker@localhost:5432/postgres" +} diff --git a/starter/shared/docker-compose/docker-compose-entrypoint.sh b/starter/infra/postgresql-knex/docker-compose/docker-compose-entrypoint.sh similarity index 100% rename from starter/shared/docker-compose/docker-compose-entrypoint.sh rename to starter/infra/postgresql-knex/docker-compose/docker-compose-entrypoint.sh diff --git a/starter/shared/docker-compose/docker-compose.ci.yml b/starter/infra/postgresql-knex/docker-compose/docker-compose.ci.yml similarity index 100% rename from starter/shared/docker-compose/docker-compose.ci.yml rename to starter/infra/postgresql-knex/docker-compose/docker-compose.ci.yml diff --git a/starter/shared/docker-compose/docker-compose.local.yml b/starter/infra/postgresql-knex/docker-compose/docker-compose.local.yml similarity index 100% rename from starter/shared/docker-compose/docker-compose.local.yml rename to starter/infra/postgresql-knex/docker-compose/docker-compose.local.yml diff --git a/starter/infra/postgresql-knex/docker-compose/docker-compose.override.yml b/starter/infra/postgresql-knex/docker-compose/docker-compose.override.yml new file mode 120000 index 0000000..9912883 --- /dev/null +++ b/starter/infra/postgresql-knex/docker-compose/docker-compose.override.yml @@ -0,0 +1 @@ +docker-compose.local.yml \ No newline at end of file diff --git a/starter/shared/docker-compose/docker-compose.yml b/starter/infra/postgresql-knex/docker-compose/docker-compose.yml similarity index 89% rename from starter/shared/docker-compose/docker-compose.yml rename to starter/infra/postgresql-knex/docker-compose/docker-compose.yml index 2a8ca69..6a44bc0 100644 --- a/starter/shared/docker-compose/docker-compose.yml +++ b/starter/infra/postgresql-knex/docker-compose/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.8' services: postgres: - image: postgres:15 + image: postgres:17 environment: - POSTGRES_DB={{PROJECT_NAME}}_docker - POSTGRES_USER={{PROJECT_NAME}}_docker diff --git a/starter/infra/postgresql-knex/knexfile.ts b/starter/infra/postgresql-knex/knexfile.ts new file mode 100644 index 0000000..51d1b85 --- /dev/null +++ b/starter/infra/postgresql-knex/knexfile.ts @@ -0,0 +1,16 @@ +import { config } from './src/config.js' + +module.exports = { + client: 'pg', + connection: config.db.connectionString, + migrations: { + directory: './src/db/migrations', + stub: './src/db/migration.template.ts', + extension: 'ts', + }, + seeds: { + directory: './src/db/seeds', + stub: './src/db/seed.template.ts', + extension: 'ts', + }, +} diff --git a/starter/infra/postgresql-knex/node-app.jsonc b/starter/infra/postgresql-knex/node-app.jsonc new file mode 100644 index 0000000..a51823b --- /dev/null +++ b/starter/infra/postgresql-knex/node-app.jsonc @@ -0,0 +1,6 @@ +{ + "module": "database", + "id": "postgres-knex", + "name": "PostgreSQL with Knex", + "replace": ["docker-compose/docker-compose.yml", ".env.jsonc"] +} diff --git a/starter/infra/postgresql-knex/package.json b/starter/infra/postgresql-knex/package.json new file mode 100644 index 0000000..5ef6ac9 --- /dev/null +++ b/starter/infra/postgresql-knex/package.json @@ -0,0 +1,13 @@ +{ + "name": "infra-knex-postgresql", + "version": "1.0.0", + "description": "PostgreSQL infrastructure with Knex", + "main": "index.js", + "scripts": {}, + "author": "", + "license": "ISC", + "dependencies": { + "knex": "^3.1.0", + "pg": "^8.13.1" + } +} diff --git a/starter/infra/postgresql-knex/src/adapters/knex.database.test.ts b/starter/infra/postgresql-knex/src/adapters/knex.database.test.ts new file mode 100644 index 0000000..d7f120c --- /dev/null +++ b/starter/infra/postgresql-knex/src/adapters/knex.database.test.ts @@ -0,0 +1,21 @@ +import { knexConnection } from './knex.database.js' +import { config } from '../config.js' +import { describe, test } from 'mocha' +import assert from 'node:assert' +import { Knex } from 'knex' + +describe('knexConnection', () => { + test('connects to PostgreSQL and prints version', async () => { + let db: Knex | undefined + + await assert.doesNotReject( + knexConnection.connect(config.db.connectionString).then(connection => { + db = connection + }) + ) + assert(db) + const version = await db.raw('SELECT version()') + assert(version.rows.length === 1) + await assert.doesNotReject(knexConnection.disconnect(db)) + }) +}) diff --git a/starter/infra/postgresql-knex/src/adapters/knex.database.ts b/starter/infra/postgresql-knex/src/adapters/knex.database.ts new file mode 100644 index 0000000..42004ae --- /dev/null +++ b/starter/infra/postgresql-knex/src/adapters/knex.database.ts @@ -0,0 +1,14 @@ +import { DbConnection } from '../domain/ports/database.js' +import knex, { Knex } from 'knex' + +export const knexConnection: DbConnection = { + connect: async (connectionString: string) => { + return knex({ + client: 'pg', + connection: connectionString, + }) + }, + disconnect: async (db: Knex) => { + await db.destroy() + }, +} diff --git a/starter/infra/postgresql-knex/src/adapters/repositories/migration.repository.ts b/starter/infra/postgresql-knex/src/adapters/repositories/migration.repository.ts new file mode 100644 index 0000000..33c1086 --- /dev/null +++ b/starter/infra/postgresql-knex/src/adapters/repositories/migration.repository.ts @@ -0,0 +1,24 @@ +import { + Migration, + MigrationRepository, +} from '../../domain/ports/repositories/migration.repository.js' +import { Knex } from 'knex' + +const TABLE = 'knex_migrations' + +const mapMigrationToDomain = (migration: any): Migration => { + return { + id: migration.id, + name: migration.name, + executedAt: migration.migration_time, + } +} + +export const createMigrationsRepository: (knex: Knex) => MigrationRepository = ( + knex: Knex +) => ({ + list: async () => { + const migrations = await knex.select('*').from(TABLE) + return migrations.map(mapMigrationToDomain) + }, +}) diff --git a/starter/infra/postgresql-knex/src/config.ts b/starter/infra/postgresql-knex/src/config.ts new file mode 100644 index 0000000..79848bb --- /dev/null +++ b/starter/infra/postgresql-knex/src/config.ts @@ -0,0 +1,14 @@ +import { createLoader, maskedValues, values } from 'configuru' + +const loader = createLoader({ + defaultConfigPath: '.env.jsonc', +}) + +const configSchema = { + db: { + connectionString: loader.string('DB_CONNECTION_STRING'), + }, +} + +export const config = values(configSchema) +export const safeConfig = maskedValues(configSchema) diff --git a/starter/infra/postgresql-knex/src/container.ts b/starter/infra/postgresql-knex/src/container.ts new file mode 100644 index 0000000..a6324ac --- /dev/null +++ b/starter/infra/postgresql-knex/src/container.ts @@ -0,0 +1,23 @@ +import { Knex } from 'knex' +import { knexConnection } from './adapters/knex.database.js' +import { createMigrationsRepository } from './adapters/repositories/migration.repository.js' +import { config } from './config.js' +import { MigrationRepository } from './domain/ports/repositories/migration.repository.js' + +export interface Container { + database: Knex + repositories: { + migrations: MigrationRepository + } +} + +export const createContainer = async (): Promise => { + const database = await knexConnection.connect(config.db.connectionString) + + return { + database, + repositories: { + migrations: createMigrationsRepository(database), + }, + } +} diff --git a/starter/infra/postgresql-knex/src/db/migration.template.ts b/starter/infra/postgresql-knex/src/db/migration.template.ts new file mode 100644 index 0000000..da29e13 --- /dev/null +++ b/starter/infra/postgresql-knex/src/db/migration.template.ts @@ -0,0 +1,4 @@ +import { Knex } from 'knex' + +export const up = (knex: Knex) => knex +export const down = () => Promise.resolve(/* no-op */) diff --git a/starter/infra/postgresql-knex/src/db/migrations/.gitkeep b/starter/infra/postgresql-knex/src/db/migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/starter/infra/postgresql-knex/src/db/seed.template.ts b/starter/infra/postgresql-knex/src/db/seed.template.ts new file mode 100644 index 0000000..1711ebb --- /dev/null +++ b/starter/infra/postgresql-knex/src/db/seed.template.ts @@ -0,0 +1,3 @@ +import { Knex } from 'knex' + +export const seed = (knex: Knex) => knex diff --git a/starter/infra/postgresql-knex/src/db/seeds/.gitkeep b/starter/infra/postgresql-knex/src/db/seeds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/starter/infra/postgresql-knex/src/domain/ports/database.d.ts b/starter/infra/postgresql-knex/src/domain/ports/database.d.ts new file mode 100644 index 0000000..8dee73a --- /dev/null +++ b/starter/infra/postgresql-knex/src/domain/ports/database.d.ts @@ -0,0 +1,4 @@ +export interface DbConnection { + connect: (connectionString: string) => Promise + disconnect: (db: Db) => Promise +} diff --git a/starter/infra/postgresql-knex/src/domain/ports/repositories/migration.repository.d.ts b/starter/infra/postgresql-knex/src/domain/ports/repositories/migration.repository.d.ts new file mode 100644 index 0000000..e43825a --- /dev/null +++ b/starter/infra/postgresql-knex/src/domain/ports/repositories/migration.repository.d.ts @@ -0,0 +1,9 @@ +export interface Migration { + id: number + name: string + executedAt: Date +} + +export interface MigrationRepository { + list: () => Promise +} diff --git a/starter/infra/postgresql-knex/src/test/setup.ts b/starter/infra/postgresql-knex/src/test/setup.ts new file mode 100644 index 0000000..d79c1b0 --- /dev/null +++ b/starter/infra/postgresql-knex/src/test/setup.ts @@ -0,0 +1,16 @@ +import { knexConnection } from '../adapters/knex.database.js' +import { config } from '../config.js' +import { Knex } from 'knex' +import { before, after } from 'mocha' + +let db: Knex + +before(async () => { + db = await knexConnection.connect(config.db.connectionString) +}) + +after(async () => { + if (db) { + await knexConnection.disconnect(db) + } +}) diff --git a/starter/shared/.gitlab-ci.yml b/starter/pipeline/cloudrun-gitlab/.gitlab-ci.yml similarity index 92% rename from starter/shared/.gitlab-ci.yml rename to starter/pipeline/cloudrun-gitlab/.gitlab-ci.yml index 51c0716..96d8ddc 100644 --- a/starter/shared/.gitlab-ci.yml +++ b/starter/pipeline/cloudrun-gitlab/.gitlab-ci.yml @@ -1,6 +1,14 @@ +# Define environments in GitLab UI with vars according to the branches for the pipeline +# ENVIRONMENT={{develpoment/stage/production}} +# GCP_PROJECT_ID={{PROJECT_NAME}} +# GCP_REGION={{europe-west3}} +# GCP_SECRETS_NAME={{PROJECT_NAME}} +# GCP_SECRETS_VERSION=latest +# GCP_SA_KEY={{base64 encoded string with SA key to deploy Cloud Run}} +# GCP_CLOUD_RUN_SA_NAME={{name of the service account for Cloud Run}} + variables: # Default configuration, check .export_variables job for calculated env variables based on branch config - # Node image for pipeline runner NODE_BASE_IMAGE: node:24.5.0 # Where to store json secrets from Cloud provider @@ -41,11 +49,6 @@ stages: # any of the branch configuration, docker image or CI SA .export_variables: before_script: - - source ci-branch-config/common.env - - | - if [ -f "ci-branch-config/${CI_COMMIT_REF_NAME}.env" ]; then - source ci-branch-config/${CI_COMMIT_REF_NAME}.env - fi - export DOCKER_REGISTRY_URL="$GCP_REGION-docker.pkg.dev" - export DOCKER_IMAGE_NAME="$DOCKER_REGISTRY_URL/$GCP_PROJECT_ID/${GCP_PROJECT_ID}-docker/$CI_PROJECT_NAME" - export DOCKER_IMAGE_BUILDER_NAME="$DOCKER_IMAGE_NAME-builder" @@ -167,7 +170,10 @@ build and push to registry: - build image - npm audit - test + environment: + name: $CI_COMMIT_REF_NAME only: + - development - stage - master @@ -193,7 +199,10 @@ deploy cloud run: --set-secrets=$SECRETS_PATH="$GCP_SECRETS_NAME:$GCP_SECRETS_VERSION" \ --set-cloudsql-instances="$GCP_PROJECT_ID:$GCP_REGION:$GCP_SQL_INSTANCE_NAME" only: + - development - stage - master + environment: + name: $CI_COMMIT_REF_NAME needs: - build and push to registry diff --git a/starter/pipeline/cloudrun-gitlab/node-app.jsonc b/starter/pipeline/cloudrun-gitlab/node-app.jsonc new file mode 100644 index 0000000..6e78f19 --- /dev/null +++ b/starter/pipeline/cloudrun-gitlab/node-app.jsonc @@ -0,0 +1,6 @@ +{ + "module": "pipeline", + "id": "cloudrun-gitlab", + "name": "CloudRun for GitLab", + "replace": [".gitlab-ci.yml"] +} diff --git a/starter/shared/ci-branch-config/common.env b/starter/shared/ci-branch-config/common.env deleted file mode 100644 index 1304062..0000000 --- a/starter/shared/ci-branch-config/common.env +++ /dev/null @@ -1,7 +0,0 @@ -ENVIRONMENT=development -GCP_PROJECT_ID={{PROJECT_NAME}}-development -GCP_REGION=europe-west3 -GCP_SECRETS_NAME={{PROJECT_NAME}}-development-config -GCP_SECRETS_VERSION=latest -GCP_SA_KEY=$SECRET_GCP_SA_KEY_DEVELOPMENT -GCP_CLOUD_RUN_SA_NAME=REPLACEME diff --git a/starter/shared/ci-branch-config/development.env b/starter/shared/ci-branch-config/development.env deleted file mode 100644 index fd449c2..0000000 --- a/starter/shared/ci-branch-config/development.env +++ /dev/null @@ -1,7 +0,0 @@ -ENVIRONMENT=development -GCP_PROJECT_ID={{PROJECT_NAME}}-development -GCP_REGION=europe-west3 -GCP_SECRETS_NAME={{PROJECT_NAME}}-development-config -GCP_SECRETS_VERSION=latest -GCP_SA_KEY=$SECRET_GCP_SA_KEY_DEVELOPMENT -GCP_CLOUD_RUN_SA_NAME=REPLACEME \ No newline at end of file diff --git a/starter/shared/ci-branch-config/master.env b/starter/shared/ci-branch-config/master.env deleted file mode 100644 index 317e809..0000000 --- a/starter/shared/ci-branch-config/master.env +++ /dev/null @@ -1,7 +0,0 @@ -ENVIRONMENT=production -GCP_PROJECT_ID={{PROJECT_NAME}}-production -GCP_REGION=europe-west3 -GCP_SECRETS_NAME={{PROJECT_NAME}}-production-config -GCP_SECRETS_VERSION=latest -GCP_SA_KEY=$SECRET_GCP_SA_KEY_PRODUCTION -GCP_CLOUD_RUN_SA_NAME=REPLACEME diff --git a/starter/shared/ci-branch-config/stage.env b/starter/shared/ci-branch-config/stage.env deleted file mode 100644 index 02f856d..0000000 --- a/starter/shared/ci-branch-config/stage.env +++ /dev/null @@ -1,7 +0,0 @@ -ENVIRONMENT=stage -GCP_PROJECT_ID={{PROJECT_NAME}}-stage -GCP_REGION=europe-west3 -GCP_SECRETS_NAME={{PROJECT_NAME}}-stage-config -GCP_SECRETS_VERSION=latest -GCP_SA_KEY=$SECRET_GCP_SA_KEY_PRODUCTION -GCP_CLOUD_RUN_SA_NAME=REPLACEME \ No newline at end of file diff --git a/starter/shared/docker-compose/docker-compose.override.yml b/starter/shared/docker-compose/docker-compose.override.yml deleted file mode 100644 index 197a108..0000000 --- a/starter/shared/docker-compose/docker-compose.override.yml +++ /dev/null @@ -1,5 +0,0 @@ -version: '3.8' -services: - postgres: - ports: - - 5432:5432 diff --git a/starter/shared/jest.config.js b/starter/shared/jest.config.js deleted file mode 100644 index 93ab1ff..0000000 --- a/starter/shared/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - preset: 'ts-jest', - roots: ['/src'], - transform: { - '^.+\\.(t|j)sx?$': 'ts-jest', - }, - testEnvironment: 'node', - testMatch: ['/src/**/*.test.ts'], - collectCoverageFrom: ['/src/app/**/*.(t|j)s'], - moduleFileExtensions: ['ts', 'js', 'json', 'node'], - modulePaths: ['/src/'], -}