diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..ef394ef --- /dev/null +++ b/.eslintrc @@ -0,0 +1,12 @@ +{ + "extends": "@antfu", + "rules": { + "no-console": "warn" + }, + "ignorePatterns": [ + "dist", + "node_modules", + "old", + "src/**/__tests__/*.ts", + ] +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index d0a9746..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: -- package-ecosystem: npm - directory: "/" - schedule: - interval: daily diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38906a4..c7bdf7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,67 +1,65 @@ -name: CI +name: Main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true on: push: branches: - - develop + - main + pull_request: - types: - - 'synchronize' - - 'opened' branches: - - '**' + - main jobs: - build-and-test: - name: Build and Test (Node ${{ matrix.node }}) - runs-on: ubuntu-latest - timeout-minutes: 30 + build-test: + name: ๐Ÿ“š Main + runs-on: ${{ matrix.os }} + strategy: matrix: + os: [ubuntu-latest] node: - 18.x - 16.x - 14.x - - 12.x - steps: - - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node }} - - uses: actions/checkout@v2 - - name: Restore Dependency Cache - uses: actions/cache@v1 - with: - path: ~/.npm - key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} - - run: npm install - - run: npm run lint - - run: npm run build - - run: npm test - deploy: - name: Deploy - runs-on: ubuntu-latest - if: ${{ github.ref == 'refs/heads/stable' }} - timeout-minutes: 30 - needs: - - build-and-test + steps: - - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc - - uses: actions/setup-node@v1 - with: - node-version: 16.x - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Restore Dependency Cache - uses: actions/cache@v1 + + - uses: pnpm/action-setup@v2.2.4 + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + name: Setup pnpm cache with: - path: ~/.npm - key: ${{ runner.OS }}-dependency-cache-${{ hashFiles('**/package.json') }} - - run: npm install - - run: npm run publish:ci + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-main-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store-main- + + - name: ๐Ÿ“ฆ Install deps (with cache) + run: pnpm install --child-concurrency 3 + + - name: ๐Ÿ‘€ Lint + run: pnpm lint + + - name: ๐Ÿš€ Build + run: pnpm build + + - name: ๐Ÿงช Test + run: pnpm test env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - GIT_AUTHOR_NAME: Ionitron - GIT_AUTHOR_EMAIL: hi@ionicframework.com - GIT_COMMITTER_NAME: Ionitron - GIT_COMMITTER_EMAIL: hi@ionicframework.com + VITE_TEST_DB_URL: ${{ secrets.VITE_TEST_DB_URL }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2f0c8c0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v3 + with: + node-version: 16.x + + - run: npx changelogithub + env: + GITHUB_TOKEN: ${{secrets.REPOCHANGELOG_TOKEN}} \ No newline at end of file diff --git a/.gitignore b/.gitignore index dd80c18..80ef718 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -*.swp -dist -node_modules +*.log .DS_Store -.vscode +node_modules +dist +package-lock.json +old \ No newline at end of file diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec..0000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 173ff47..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname $0)/_/husky.sh" - -npm run lint diff --git a/.npmrc b/.npmrc index 43c97e7..a29b715 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,3 @@ -package-lock=false +enable-pre-post-scripts=true +shamefully-hoist=true +git-checks=false \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 09463f1..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,229 +0,0 @@ -## [1.7.2](https://github.com/ionic-team/native-run/compare/v1.7.1...v1.7.2) (2023-03-02) - - -### Bug Fixes - -* NodeJS 18 compat ([#275](https://github.com/ionic-team/native-run/issues/275)) ([45050bb](https://github.com/ionic-team/native-run/commit/45050bbd416692e0911fe73a67d789b205e48ecc)) - -## [1.7.1](https://github.com/ionic-team/native-run/compare/v1.7.0...v1.7.1) (2022-09-23) - - -### Bug Fixes - -* **android:** Use arm64 architecture on emulator creation from M1 ([#258](https://github.com/ionic-team/native-run/issues/258)) ([a6501c4](https://github.com/ionic-team/native-run/commit/a6501c419834f08bfd2be9ef00d0a6b1f4ee5f8a)) - -# [1.7.0](https://github.com/ionic-team/native-run/compare/v1.6.0...v1.7.0) (2022-09-01) - - -### Features - -* **android:** add API 33 support ([#245](https://github.com/ionic-team/native-run/issues/245)) ([8f1717d](https://github.com/ionic-team/native-run/commit/8f1717d1a54eaf9f45688c0c243f2085abd61421)) - -# [1.6.0](https://github.com/ionic-team/native-run/compare/v1.5.0...v1.6.0) (2022-05-16) - - -### Features - -* **android:** add API 32 support ([#232](https://github.com/ionic-team/native-run/issues/232)) ([bc48231](https://github.com/ionic-team/native-run/commit/bc482319c77c79c0da77b769865ab070c68efb67)) - -# [1.5.0](https://github.com/ionic-team/native-run/compare/v1.4.1...v1.5.0) (2021-10-11) - - -### Bug Fixes - -* Throw ERR_UNSUPPORTED_API_LEVEL ([#204](https://github.com/ionic-team/native-run/issues/204)) ([b879744](https://github.com/ionic-team/native-run/commit/b879744c81bbc6b73c6a1a97064dcc51818b2fa5)) - - -### Features - -* **android:** support API 31 ([#203](https://github.com/ionic-team/native-run/issues/203)) ([fb64ca5](https://github.com/ionic-team/native-run/commit/fb64ca5165cad0fe029ef81e9c8ba11ca36bc08c)) - -## [1.4.1](https://github.com/ionic-team/native-run/compare/v1.4.0...v1.4.1) (2021-09-03) - - -### Bug Fixes - -* throw iOS errors that are not DeviceLocked ([#200](https://github.com/ionic-team/native-run/issues/200)) ([3ac6914](https://github.com/ionic-team/native-run/commit/3ac6914d7f9672fada40e80a2b0a9bd156e27db0)) - -# [1.4.0](https://github.com/ionic-team/native-run/compare/v1.3.1...v1.4.0) (2021-06-08) - - -### Features - -* **android:** support API 30 ([#186](https://github.com/ionic-team/native-run/issues/186)) ([e90aa32](https://github.com/ionic-team/native-run/commit/e90aa328666a353a015e47153b03f6896877890a)) - -## [1.3.1](https://github.com/ionic-team/native-run/compare/v1.3.0...v1.3.1) (2021-06-04) - - -### Bug Fixes - -* don't print retry message for --json ([#184](https://github.com/ionic-team/native-run/issues/184)) ([4fb0563](https://github.com/ionic-team/native-run/commit/4fb0563d96435482066a270595b7f3393a0e6b42)) - -# [1.3.0](https://github.com/ionic-team/native-run/compare/v1.2.2...v1.3.0) (2020-12-07) - - -### Features - -* **iOS:** Add 5 second retry on DeviceLocked for iOS ([#167](https://github.com/ionic-team/native-run/issues/167)) ([f451e46](https://github.com/ionic-team/native-run/commit/f451e46a7f4d05c27baa641530d00f1301e2bfd5)) - -## [1.2.2](https://github.com/ionic-team/native-run/compare/v1.2.1...v1.2.2) (2020-10-16) - - -### Bug Fixes - -* **android:** don't print ADB unresponsive error to stdout ([#163](https://github.com/ionic-team/native-run/issues/163)) ([2cd894b](https://github.com/ionic-team/native-run/commit/2cd894ba2341937f19825cb0865dd885acb01ace)) - -## [1.2.1](https://github.com/ionic-team/native-run/compare/v1.2.0...v1.2.1) (2020-09-29) - - -### Bug Fixes - -* add missing signal-exit dependency ([#158](https://github.com/ionic-team/native-run/issues/158)) ([18743e0](https://github.com/ionic-team/native-run/commit/18743e0d48212f503393b47a21ced9905a24fcea)) - -# [1.2.0](https://github.com/ionic-team/native-run/compare/v1.1.0...v1.2.0) (2020-09-28) - - -### Bug Fixes - -* **iOS:** implement iOS 14 compatibility ([#157](https://github.com/ionic-team/native-run/issues/157)) ([6f242fd](https://github.com/ionic-team/native-run/commit/6f242fd9aa1dea2cd96db13f21b981b21953f3ea)) - - -### Features - -* **android:** gracefully handle when device is offline ([aa6688d](https://github.com/ionic-team/native-run/commit/aa6688d257127c5cf6b24279a6eb506cf5b8c258)) -* **android:** gracefully handle when device is out of space ([9da9f59](https://github.com/ionic-team/native-run/commit/9da9f5968cebdc7887230f3085dfd7c2d5a4f3ec)) -* **android:** handle INSTALL_FAILED_INSUFFICIENT_STORAGE adb error ([bcf2369](https://github.com/ionic-team/native-run/commit/bcf2369b51e6afcd3230eb68db965fe2a89300e1)) -* **android:** kill unresponsive adb server after 5s and retry ([9e1bbc7](https://github.com/ionic-team/native-run/commit/9e1bbc7d636a266ed472e6b43553781bc7e90896)) -* **list:** show model, then ID if no name ([d56415d](https://github.com/ionic-team/native-run/commit/d56415d00c68ce288d6575ebf4cb0386f6070801)) -* columnize `--list` output ([5b7da72](https://github.com/ionic-team/native-run/commit/5b7da7235c23b01185d8317bf5e4cdad878a9845)) - -# [1.1.0](https://github.com/ionic-team/native-run/compare/v1.0.0...v1.1.0) (2020-09-10) - - -### Bug Fixes - -* **ios:** do not falsely link to Android Wiki for iOS errors ([18371f2](https://github.com/ionic-team/native-run/commit/18371f296fb8a3cb0ab070f2c5316f98e9351263)) - - -### Features - -* **android:** create AVD home if not found ([1cec3c2](https://github.com/ionic-team/native-run/commit/1cec3c258b26c876bf12f8d823ef270faa4a6a78)) - -# [1.0.0](https://github.com/ionic-team/native-run/compare/v0.3.0...v1.0.0) (2020-04-02) - - -### chore - -* require Node 10 ([430d23a](https://github.com/ionic-team/native-run/commit/430d23ac5dfb4f5c0ab059e923839a6bd7d523d4)) - - -### Features - -* **android:** handle adb error re: improper signing ([829585f](https://github.com/ionic-team/native-run/commit/829585f82cab311f5ceee84369ccdac2b327d744)) -* **android:** show link to online help docs for errors ([0bc4487](https://github.com/ionic-team/native-run/commit/0bc448715af72ba7febee4f8f3e5b008cd489f16)) - - -### BREAKING CHANGES - -* A minimum of Node.js 10.3.0 is required. - -# [0.3.0](https://github.com/ionic-team/native-run/compare/v0.2.9...v0.3.0) (2019-12-04) - - -### Features - -* **android:** handle INSTALL_FAILED_OLDER_SDK adb error ([#92](https://github.com/ionic-team/native-run/issues/92)) ([6616f37](https://github.com/ionic-team/native-run/commit/6616f379a60797650709ba7a70f195558ddcdedd)) -* **android:** support API 29 ([2282b3a](https://github.com/ionic-team/native-run/commit/2282b3acfa58da685b0dc1981cf602a781bd6a1a)) - -## [0.2.9](https://github.com/ionic-team/native-run/compare/v0.2.8...v0.2.9) (2019-10-15) - - -### Bug Fixes - -* **ios:** added support for iOS 13 ([c27675f](https://github.com/ionic-team/native-run/commit/c27675f20ef40264837af5cf091e94bd1af2db91)) - -## [0.2.8](https://github.com/ionic-team/native-run/compare/v0.2.7...v0.2.8) (2019-07-12) - - -### Bug Fixes - -* **list:** include errors in standard output ([9ceb343](https://github.com/ionic-team/native-run/commit/9ceb343)) - -## [0.2.7](https://github.com/ionic-team/native-run/compare/v0.2.6...v0.2.7) (2019-06-25) - - -### Bug Fixes - -* **android:** more accurate device/emulator detection ([5ec454b](https://github.com/ionic-team/native-run/commit/5ec454b)) -* **list:** handle errors with devices/virtual devices ([9c2375d](https://github.com/ionic-team/native-run/commit/9c2375d)) - -## [0.2.6](https://github.com/ionic-team/native-run/compare/v0.2.5...v0.2.6) (2019-06-17) - - -### Bug Fixes - -* **ios:** support old simctl runtime output format ([aa73578](https://github.com/ionic-team/native-run/commit/aa73578)) - -## [0.2.5](https://github.com/ionic-team/native-run/compare/v0.2.4...v0.2.5) (2019-06-10) - - -### Bug Fixes - -* **android:** fix path issue for windows ([9b87583](https://github.com/ionic-team/native-run/commit/9b87583)) - -## [0.2.4](https://github.com/ionic-team/native-run/compare/v0.2.3...v0.2.4) (2019-06-07) - - -### Bug Fixes - -* **android:** log errors during sdk walk, don't throw ([ea2e0c5](https://github.com/ionic-team/native-run/commit/ea2e0c5)) - -## [0.2.3](https://github.com/ionic-team/native-run/compare/v0.2.2...v0.2.3) (2019-06-05) - - -### Bug Fixes - -* **ios:** fix getSimulators for Xcode 10+ tooling ([605164a](https://github.com/ionic-team/native-run/commit/605164a)) -* **ios:** improve getSimulators error messaging ([86205d6](https://github.com/ionic-team/native-run/commit/86205d6)) - -## [0.2.2](https://github.com/ionic-team/native-run/compare/v0.2.1...v0.2.2) (2019-05-31) - - -### Bug Fixes - -* **android:** handle devices connected over tcp/ip ([4869f4a](https://github.com/ionic-team/native-run/commit/4869f4a)) - -## [0.2.1](https://github.com/ionic-team/native-run/compare/v0.2.0...v0.2.1) (2019-05-30) - - -### Bug Fixes - -* **android:** handle \r\n for adb output on Windows during --list ([50bfa73](https://github.com/ionic-team/native-run/commit/50bfa73)) - -# [0.2.0](https://github.com/ionic-team/native-run/compare/v0.1.2...v0.2.0) (2019-05-30) - - -### Bug Fixes - -* **ios:** log iOS --list errors, but still print ([e516a83](https://github.com/ionic-team/native-run/commit/e516a83)) -* **ios:** print more helpful error if app path doesn't exist ([49819b0](https://github.com/ionic-team/native-run/commit/49819b0)) - - -### Features - -* **android:** better error messaging ([0cfa51a](https://github.com/ionic-team/native-run/commit/0cfa51a)) -* **android:** have --forward accept multiple values ([#26](https://github.com/ionic-team/native-run/issues/26)) ([7844ea4](https://github.com/ionic-team/native-run/commit/7844ea4)) - -## [0.1.2](https://github.com/ionic-team/native-run/compare/v0.1.1...v0.1.2) (2019-05-29) - - -### Bug Fixes - -* **android:** catch api issues for --list ([9453f2c](https://github.com/ionic-team/native-run/commit/9453f2c)) - -## [0.1.1](https://github.com/ionic-team/native-run/compare/v0.1.0...v0.1.1) (2019-05-29) - - -### Bug Fixes - -* **list:** add heading for each platform ([203d7b6](https://github.com/ionic-team/native-run/commit/203d7b6)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 8ab215f..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,38 +0,0 @@ -# Contributing - -Pull requests are welcome! - -To begin, clone the repo, then install dependencies and setup the project. - -``` -npm install -npm run setup -``` - -The source code is written in TypeScript. Spin up the compiler to watch for source changes: - -``` -npm run watch -``` - -## Publishing - -CI automatically publishes the next version semantically from analyzing commits in `stable`. To maintain a shared history between `develop` and `stable`, the branches must be rebased with each other locally. - -* When it's time to cut a release from `develop`: - - ``` - git checkout stable - git merge --ff-only develop - git push origin stable - ``` - -* Await successful publish in CI. Ionitron will push the updated versions and tags to `stable`. -* Sync `develop` with `stable`. - - ``` - git pull origin stable - git checkout develop - git merge --ff-only stable - git push origin develop - ``` diff --git a/README.md b/README.md index 735a964..d710e29 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ To install, run: npm install -g native-run ``` -:memo: Requires NodeJS 10+ +:memo: Requires NodeJS 14+ ## Usage diff --git a/bin/native-run b/bin/native-run deleted file mode 100755 index 888f147..0000000 --- a/bin/native-run +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -process.title = 'native-run'; - -if (process.argv.includes('--verbose')) { - process.env.DEBUG = '*'; -} - -require('../').run(); diff --git a/bin/native-run.js b/bin/native-run.js new file mode 100755 index 0000000..3bf8d24 --- /dev/null +++ b/bin/native-run.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node + +'use strict' + +process.title = 'native-run' + +if (process.argv.includes('--verbose')) + process.env.DEBUG = '*' + +require('../dist').run() diff --git a/bin/native-run.mjs b/bin/native-run.mjs new file mode 100755 index 0000000..b6f3403 --- /dev/null +++ b/bin/native-run.mjs @@ -0,0 +1,6 @@ +#!/usr/bin/env node +process.title = 'native-run' +if (process.argv.includes('--verbose')) + process.env.DEBUG = '*' + +import('../dist').run() diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index a51134b..0000000 --- a/jest.config.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - preset: 'ts-jest', - globals: { - 'ts-jest': { - diagnostics: { - // warnOnly: true, - }, - tsConfig: { - types: [ - "node", - "jest", - ], - }, - }, - }, -}; diff --git a/package.json b/package.json index 1365cb7..459b2f2 100644 --- a/package.json +++ b/package.json @@ -3,36 +3,73 @@ "version": "1.7.2", "description": "A CLI for running apps on iOS/Android devices and simulators/emulators", "bin": { - "native-run": "bin/native-run" + "native-run": "bin/native-run.js", + "native-run-esm": "bin/native-run-esm.mjs" }, - "scripts": { - "clean": "rm -rf dist", - "build": "npm run clean && tsc", - "watch": "tsc -w", - "test": "jest --maxWorkers=4", - "lint": "npm run eslint && npm run prettier -- --check", - "fmt": "npm run eslint -- --fix && npm run prettier -- --write", - "prettier": "prettier \"**/*.ts\"", - "eslint": "eslint . --ext .ts", - "publish:ci": "semantic-release", - "publish:testing": "npm version prerelease --preid=testing --no-git-tag-version && npm publish --tag=testing && git stash", - "prepublishOnly": "npm run build", - "setup": "husky install" + "author": "Ionic Team (https://ionicframework.com)", + "license": "MIT", + "bugs": { + "url": "https://github.com/ionic-team/native-run/issues" + }, + "homepage": "https://github.com/ionic-team/native-run#readme", + "keywords": [ + "android", + "ios", + "cli", + "mobile", + "app", + "hybrid", + "native" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/native-run.git" + }, + "engines": { + "node": ">=14" + }, + "packageManager": "pnpm@7.28.0", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "require": "./dist/index.js" + }, + "./android": { + "import": "./dist/android/index.mjs", + "types": "./dist/android/index.d.ts", + "require": "./dist/android/index.js" + }, + "./ios": { + "import": "./dist/ios/index.mjs", + "types": "./dist/ios/index.d.ts", + "require": "./dist/ios/index.js" + }, + "./util": { + "import": "./dist/util/*.mjs", + "types": "./dist/util/*.d.ts", + "require": "./dist/util/*.js" + } }, - "main": "dist/index.js", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", "files": [ "assets", "bin", "dist" ], - "engines": { - "node": ">=12.13.0" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/ionic-team/native-run.git" + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "prepublishOnly": "pnpm run build", + "release": "pnpm build && bumpp --commit --push --tag && pnpm publish", + "lint": "eslint --ext .ts,.tsx,.js,.jsx .", + "lint:fix": "eslint --ext .ts,.tsx,.js,.jsx . --fix", + "test": "vitest", + "test:watch": "vitest --watch" }, - "dependencies": { + "peerDependencies": { "@ionic/utils-fs": "^3.1.6", "@ionic/utils-terminal": "^2.3.3", "bplist-parser": "^0.3.2", @@ -46,63 +83,42 @@ "yauzl": "^2.10.0" }, "devDependencies": { + "@antfu/eslint-config": "^0.36.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^1.0.1", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-terminal": "^2.3.3", "@semantic-release/changelog": "^6.0.1", "@semantic-release/git": "^10.0.1", "@types/debug": "^4.1.7", "@types/elementtree": "^0.1.1", "@types/ini": "^1.3.31", - "@types/jest": "^26.0.13", - "@types/node": "^10.17.14", + "@types/node": "^18.15.0", "@types/plist": "^3.0.2", "@types/split2": "^3.2.1", "@types/through2": "^2.0.34", "@types/yauzl": "^2.10.0", - "eslint": "^7.8.1", + "@vitest/coverage-c8": "^0.29.2", + "bplist-parser": "^0.3.2", + "bumpp": "^9.0.0", + "debug": "^4.3.4", + "elementtree": "^0.1.7", + "eslint": "^8.35.0", "husky": "^5.0.4", - "jest": "^26.4.2", + "ini": "^3.0.1", + "plist": "^3.0.6", "prettier": "^2.2.1", "semantic-release": "^19.0.5", - "ts-jest": "^26.3.0", - "typescript": "~4.1.2" - }, - "prettier": "@ionic/prettier-config", - "eslintConfig": { - "extends": "@ionic/eslint-config/recommended", - "rules": { - "@typescript-eslint/explicit-module-boundary-types": [ - "warn", - { - "allowArgumentsExplicitlyTypedAsAny": true - } - ] - } - }, - "release": { - "branches": "stable", - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/changelog", - "@semantic-release/npm", - "@semantic-release/github", - "@semantic-release/git" - ] - }, - "keywords": [ - "android", - "ios", - "cli", - "mobile", - "app", - "hybrid", - "native" - ], - "author": "Ionic Team (https://ionicframework.com)", - "license": "MIT", - "bugs": { - "url": "https://github.com/ionic-team/native-run/issues" + "split2": "^4.1.0", + "through2": "^4.0.2", + "tslib": "^2.4.0", + "tsup": "^6.6.3", + "typescript": "^4.9.5", + "vite": "^4.1.4", + "vitest": "^0.29.2", + "yauzl": "^2.10.0" }, - "homepage": "https://github.com/ionic-team/native-run#readme" -} + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..cbb97cf --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5558 @@ +lockfileVersion: 5.4 + +specifiers: + '@antfu/eslint-config': ^0.36.0 + '@ionic/eslint-config': ^0.3.0 + '@ionic/prettier-config': ^1.0.1 + '@ionic/utils-fs': ^3.1.6 + '@ionic/utils-terminal': ^2.3.3 + '@semantic-release/changelog': ^6.0.1 + '@semantic-release/git': ^10.0.1 + '@types/debug': ^4.1.7 + '@types/elementtree': ^0.1.1 + '@types/ini': ^1.3.31 + '@types/node': ^18.15.0 + '@types/plist': ^3.0.2 + '@types/split2': ^3.2.1 + '@types/through2': ^2.0.34 + '@types/yauzl': ^2.10.0 + '@vitest/coverage-c8': ^0.29.2 + bplist-parser: ^0.3.2 + bumpp: ^9.0.0 + debug: ^4.3.4 + elementtree: ^0.1.7 + eslint: ^8.35.0 + husky: ^5.0.4 + ini: ^3.0.1 + plist: ^3.0.6 + prettier: ^2.2.1 + semantic-release: ^19.0.5 + split2: ^4.1.0 + through2: ^4.0.2 + tslib: ^2.4.0 + tsup: ^6.6.3 + typescript: ^4.9.5 + vite: ^4.1.4 + vitest: ^0.29.2 + yauzl: ^2.10.0 + +devDependencies: + '@antfu/eslint-config': 0.36.0_ycpbpc6yetojsgtrx3mwntkhsu + '@ionic/eslint-config': 0.3.0_ycpbpc6yetojsgtrx3mwntkhsu + '@ionic/prettier-config': 1.0.1_prettier@2.8.4 + '@ionic/utils-fs': 3.1.6 + '@ionic/utils-terminal': 2.3.3 + '@semantic-release/changelog': 6.0.2_semantic-release@19.0.5 + '@semantic-release/git': 10.0.1_semantic-release@19.0.5 + '@types/debug': 4.1.7 + '@types/elementtree': 0.1.1 + '@types/ini': 1.3.31 + '@types/node': 18.15.0 + '@types/plist': 3.0.2 + '@types/split2': 3.2.1 + '@types/through2': 2.0.38 + '@types/yauzl': 2.10.0 + '@vitest/coverage-c8': 0.29.2_vitest@0.29.2 + bplist-parser: 0.3.2 + bumpp: 9.0.0 + debug: 4.3.4 + elementtree: 0.1.7 + eslint: 8.35.0 + husky: 5.2.0 + ini: 3.0.1 + plist: 3.0.6 + prettier: 2.8.4 + semantic-release: 19.0.5 + split2: 4.1.0 + through2: 4.0.2 + tslib: 2.5.0 + tsup: 6.6.3_typescript@4.9.5 + typescript: 4.9.5 + vite: 4.1.4_@types+node@18.15.0 + vitest: 0.29.2 + yauzl: 2.10.0 + +packages: + + /@antfu/eslint-config-basic/0.36.0_y46c5jzhegju5ppnhbs6d4llxi: + resolution: {integrity: sha512-2b3ZB7pO00nxAERDXo82iYPjLQ4l/AOMm0CTKmGmqWbN3RB33EIQWzYheZRboSbAVzWpI1/3rg/Gu+7xYVMYHA==} + peerDependencies: + eslint: '>=7.4.0' + dependencies: + eslint: 8.35.0 + eslint-plugin-antfu: 0.36.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint-plugin-eslint-comments: 3.2.0_eslint@8.35.0 + eslint-plugin-html: 7.1.0 + eslint-plugin-import: 2.27.5_ajyizmi44oc3hrc35l6ndh7p4e + eslint-plugin-jsonc: 2.6.0_eslint@8.35.0 + eslint-plugin-markdown: 3.0.0_eslint@8.35.0 + eslint-plugin-n: 15.6.1_eslint@8.35.0 + eslint-plugin-no-only-tests: 3.1.0 + eslint-plugin-promise: 6.1.1_eslint@8.35.0 + eslint-plugin-unicorn: 45.0.2_eslint@8.35.0 + eslint-plugin-unused-imports: 2.0.0_hlu2tevvfejtijvruutuci6rky + eslint-plugin-yml: 1.5.0_eslint@8.35.0 + jsonc-eslint-parser: 2.1.0 + yaml-eslint-parser: 1.1.0 + transitivePeerDependencies: + - '@typescript-eslint/eslint-plugin' + - '@typescript-eslint/parser' + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + - typescript + dev: true + + /@antfu/eslint-config-ts/0.36.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-I/h2ZOPBIqgnALG2fQp6lOBsOXk51QwLDumyEayt7GRnitdP4o9D8i+YAPowrMJ8M3kU7puQUyhWuJmZLgo57A==} + peerDependencies: + eslint: '>=7.4.0' + typescript: '>=3.9' + dependencies: + '@antfu/eslint-config-basic': 0.36.0_y46c5jzhegju5ppnhbs6d4llxi + '@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint: 8.35.0 + eslint-plugin-jest: 27.2.1_aere4n7c7ynvp62ae3ihfxuwhu + typescript: 4.9.5 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - jest + - supports-color + dev: true + + /@antfu/eslint-config-vue/0.36.0_y46c5jzhegju5ppnhbs6d4llxi: + resolution: {integrity: sha512-YuTcNlVlrEWX1ESOiPgr+e2Walfd6xt3Toa0kAKJxq2aBS1RWqIi1l3zIVGCHaX72lOrSXNmQ7bryaZyGADGDg==} + peerDependencies: + eslint: '>=7.4.0' + dependencies: + '@antfu/eslint-config-basic': 0.36.0_y46c5jzhegju5ppnhbs6d4llxi + '@antfu/eslint-config-ts': 0.36.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint: 8.35.0 + eslint-plugin-vue: 9.9.0_eslint@8.35.0 + local-pkg: 0.4.3 + transitivePeerDependencies: + - '@typescript-eslint/eslint-plugin' + - '@typescript-eslint/parser' + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - jest + - supports-color + - typescript + dev: true + + /@antfu/eslint-config/0.36.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-otZ9PfKRT3gnGMMX1gS8URTNPMPCZ69K5jHZvLkYojru0gLBZ3IO5fCvjEZpWqOyIUHtAgg6NWELf1DbEF+NDw==} + peerDependencies: + eslint: '>=7.4.0' + dependencies: + '@antfu/eslint-config-vue': 0.36.0_y46c5jzhegju5ppnhbs6d4llxi + '@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint: 8.35.0 + eslint-plugin-eslint-comments: 3.2.0_eslint@8.35.0 + eslint-plugin-html: 7.1.0 + eslint-plugin-import: 2.27.5_ajyizmi44oc3hrc35l6ndh7p4e + eslint-plugin-jsonc: 2.6.0_eslint@8.35.0 + eslint-plugin-n: 15.6.1_eslint@8.35.0 + eslint-plugin-promise: 6.1.1_eslint@8.35.0 + eslint-plugin-unicorn: 45.0.2_eslint@8.35.0 + eslint-plugin-vue: 9.9.0_eslint@8.35.0 + eslint-plugin-yml: 1.5.0_eslint@8.35.0 + jsonc-eslint-parser: 2.1.0 + yaml-eslint-parser: 1.1.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - jest + - supports-color + - typescript + dev: true + + /@babel/code-frame/7.18.6: + resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + dev: true + + /@babel/helper-validator-identifier/7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/highlight/7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@bcoe/v8-coverage/0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@colors/colors/1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm/0.16.17: + resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm/0.17.11: + resolution: {integrity: sha512-CdyX6sRVh1NzFCsf5vw3kULwlAhfy9wVt8SZlrhQ7eL2qBjGbFhRBWkkAzuZm9IIEOCKJw4DXA6R85g+qc8RDw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.16.17: + resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.17.11: + resolution: {integrity: sha512-QnK4d/zhVTuV4/pRM4HUjcsbl43POALU2zvBynmrrqZt9LPcLA3x1fTZPBg2RRguBQnJcnU059yKr+bydkntjg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.16.17: + resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.17.11: + resolution: {integrity: sha512-3PL3HKtsDIXGQcSCKtWD/dy+mgc4p2Tvo2qKgKHj9Yf+eniwFnuoQ0OUhlSfAEpKAFzF9N21Nwgnap6zy3L3MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.16.17: + resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.17.11: + resolution: {integrity: sha512-pJ950bNKgzhkGNO3Z9TeHzIFtEyC2GDQL3wxkMApDEghYx5Qers84UTNc1bAxWbRkuJOgmOha5V0WUeh8G+YGw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.16.17: + resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.17.11: + resolution: {integrity: sha512-iB0dQkIHXyczK3BZtzw1tqegf0F0Ab5texX2TvMQjiJIWXAfM4FQl7D909YfXWnB92OQz4ivBYQ2RlxBJrMJOw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.16.17: + resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.17.11: + resolution: {integrity: sha512-7EFzUADmI1jCHeDRGKgbnF5sDIceZsQGapoO6dmw7r/ZBEKX7CCDnIz8m9yEclzr7mFsd+DyasHzpjfJnmBB1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.16.17: + resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.17.11: + resolution: {integrity: sha512-iPgenptC8i8pdvkHQvXJFzc1eVMR7W2lBPrTE6GbhR54sLcF42mk3zBOjKPOodezzuAz/KSu8CPyFSjcBMkE9g==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.16.17: + resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.17.11: + resolution: {integrity: sha512-M9iK/d4lgZH0U5M1R2p2gqhPV/7JPJcRz+8O8GBKVgqndTzydQ7B2XGDbxtbvFkvIs53uXTobOhv+RyaqhUiMg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.16.17: + resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.17.11: + resolution: {integrity: sha512-Qxth3gsWWGKz2/qG2d5DsW/57SeA2AmpSMhdg9TSB5Svn2KDob3qxfQSkdnWjSd42kqoxIPy3EJFs+6w1+6Qjg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.16.17: + resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.17.11: + resolution: {integrity: sha512-dB1nGaVWtUlb/rRDHmuDQhfqazWE0LMro/AIbT2lWM3CDMHJNpLckH+gCddQyhhcLac2OYw69ikUMO34JLt3wA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.16.17: + resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.17.11: + resolution: {integrity: sha512-aCWlq70Q7Nc9WDnormntGS1ar6ZFvUpqr8gXtO+HRejRYPweAFQN615PcgaSJkZjhHp61+MNLhzyVALSF2/Q0g==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.16.17: + resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.17.11: + resolution: {integrity: sha512-cGeGNdQxqY8qJwlYH1BP6rjIIiEcrM05H7k3tR7WxOLmD1ZxRMd6/QIOWMb8mD2s2YJFNRuNQ+wjMhgEL2oCEw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.16.17: + resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.17.11: + resolution: {integrity: sha512-BdlziJQPW/bNe0E8eYsHB40mYOluS+jULPCjlWiHzDgr+ZBRXPtgMV1nkLEGdpjrwgmtkZHEGEPaKdS/8faLDA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.16.17: + resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.17.11: + resolution: {integrity: sha512-MDLwQbtF+83oJCI1Cixn68Et/ME6gelmhssPebC40RdJaect+IM+l7o/CuG0ZlDs6tZTEIoxUe53H3GmMn8oMA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.16.17: + resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.17.11: + resolution: {integrity: sha512-4N5EMESvws0Ozr2J94VoUD8HIRi7X0uvUv4c0wpTHZyZY9qpaaN7THjosdiW56irQ4qnJ6Lsc+i+5zGWnyqWqQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.16.17: + resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.17.11: + resolution: {integrity: sha512-rM/v8UlluxpytFSmVdbCe1yyKQd/e+FmIJE2oPJvbBo+D0XVWi1y/NQ4iTNx+436WmDHQBjVLrbnAQLQ6U7wlw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.16.17: + resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.17.11: + resolution: {integrity: sha512-4WaAhuz5f91h3/g43VBGdto1Q+X7VEZfpcWGtOFXnggEuLvjV+cP6DyLRU15IjiU9fKLLk41OoJfBFN5DhPvag==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.16.17: + resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.17.11: + resolution: {integrity: sha512-UBj135Nx4FpnvtE+C8TWGp98oUgBcmNmdYgl5ToKc0mBHxVVqVE7FUS5/ELMImOp205qDAittL6Ezhasc2Ev/w==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.16.17: + resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.17.11: + resolution: {integrity: sha512-1/gxTifDC9aXbV2xOfCbOceh5AlIidUrPsMpivgzo8P8zUtczlq1ncFpeN1ZyQJ9lVs2hILy1PG5KPp+w8QPPg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.16.17: + resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.17.11: + resolution: {integrity: sha512-vtSfyx5yRdpiOW9yp6Ax0zyNOv9HjOAw8WaZg3dF5djEHKKm3UnoohftVvIJtRh0Ec7Hso0RIdTqZvPXJ7FdvQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.16.17: + resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.17.11: + resolution: {integrity: sha512-GFPSLEGQr4wHFTiIUJQrnJKZhZjjq4Sphf+mM76nQR6WkQn73vm7IsacmBRPkALfpOCHsopSvLgqdd4iUW2mYw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.16.17: + resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.17.11: + resolution: {integrity: sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils/4.2.0_eslint@8.35.0: + resolution: {integrity: sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.35.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@eslint/eslintrc/2.0.0: + resolution: {integrity: sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.1 + globals: 13.20.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js/8.35.0: + resolution: {integrity: sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@ionic/eslint-config/0.3.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-Uf1hS2YIoHlcvXPF5LnsPM6auMewEdChQhR117Rt3sVEAutbyKMpFP4slNC2a6up3a5Q34zepqlf61Qgkf9XeQ==} + peerDependencies: + eslint: '>=7' + dependencies: + '@typescript-eslint/eslint-plugin': 4.33.0_7anazn7gl5tnln7tyojcuhgrj4 + '@typescript-eslint/parser': 4.33.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint: 8.35.0 + eslint-config-prettier: 6.15.0_eslint@8.35.0 + eslint-plugin-import: 2.27.5_menevh4pffsl3d4xx5zxnod25u + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + - typescript + dev: true + + /@ionic/prettier-config/1.0.1_prettier@2.8.4: + resolution: {integrity: sha512-/v8UOW7rxkw/hvrRe/QfjlQsdjkm3sfAHoE3uqffO5BoNGijQMARrT32JT9Ei0g6KySXPyxxW+7LzPHrQmfzCw==} + peerDependencies: + prettier: ^2.0.0 + dependencies: + prettier: 2.8.4 + dev: true + + /@ionic/utils-fs/3.1.6: + resolution: {integrity: sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==} + engines: {node: '>=10.3.0'} + dependencies: + '@types/fs-extra': 8.1.2 + debug: 4.3.4 + fs-extra: 9.1.0 + tslib: 2.5.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@ionic/utils-terminal/2.3.3: + resolution: {integrity: sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==} + engines: {node: '>=10.3.0'} + dependencies: + '@types/slice-ansi': 4.0.0 + debug: 4.3.4 + signal-exit: 3.0.7 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tslib: 2.5.0 + untildify: 4.0.0 + wrap-ansi: 7.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@istanbuljs/schema/0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jridgewell/resolve-uri/3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec/1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + dev: true + + /@jridgewell/trace-mapping/0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + + /@jsdevtools/ez-spawn/3.0.4: + resolution: {integrity: sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA==} + engines: {node: '>=10'} + dependencies: + call-me-maybe: 1.0.2 + cross-spawn: 7.0.3 + string-argv: 0.3.1 + type-detect: 4.0.8 + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@octokit/auth-token/3.0.3: + resolution: {integrity: sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 9.0.0 + dev: true + + /@octokit/core/4.2.0: + resolution: {integrity: sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==} + engines: {node: '>= 14'} + dependencies: + '@octokit/auth-token': 3.0.3 + '@octokit/graphql': 5.0.5 + '@octokit/request': 6.2.3 + '@octokit/request-error': 3.0.3 + '@octokit/types': 9.0.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/endpoint/7.0.5: + resolution: {integrity: sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 9.0.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.0 + dev: true + + /@octokit/graphql/5.0.5: + resolution: {integrity: sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==} + engines: {node: '>= 14'} + dependencies: + '@octokit/request': 6.2.3 + '@octokit/types': 9.0.0 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/openapi-types/16.0.0: + resolution: {integrity: sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==} + dev: true + + /@octokit/plugin-paginate-rest/6.0.0_@octokit+core@4.2.0: + resolution: {integrity: sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=4' + dependencies: + '@octokit/core': 4.2.0 + '@octokit/types': 9.0.0 + dev: true + + /@octokit/plugin-request-log/1.0.4_@octokit+core@4.2.0: + resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 4.2.0 + dev: true + + /@octokit/plugin-rest-endpoint-methods/7.0.1_@octokit+core@4.2.0: + resolution: {integrity: sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 4.2.0 + '@octokit/types': 9.0.0 + deprecation: 2.3.1 + dev: true + + /@octokit/request-error/3.0.3: + resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 9.0.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: true + + /@octokit/request/6.2.3: + resolution: {integrity: sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==} + engines: {node: '>= 14'} + dependencies: + '@octokit/endpoint': 7.0.5 + '@octokit/request-error': 3.0.3 + '@octokit/types': 9.0.0 + is-plain-object: 5.0.0 + node-fetch: 2.6.9 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/rest/19.0.7: + resolution: {integrity: sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==} + engines: {node: '>= 14'} + dependencies: + '@octokit/core': 4.2.0 + '@octokit/plugin-paginate-rest': 6.0.0_@octokit+core@4.2.0 + '@octokit/plugin-request-log': 1.0.4_@octokit+core@4.2.0 + '@octokit/plugin-rest-endpoint-methods': 7.0.1_@octokit+core@4.2.0 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/types/9.0.0: + resolution: {integrity: sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==} + dependencies: + '@octokit/openapi-types': 16.0.0 + dev: true + + /@pnpm/config.env-replace/1.0.0: + resolution: {integrity: sha512-ZVPVDi1E8oeXlYqkGRtX0CkzLTwE2zt62bjWaWKaAvI8NZqHzlMvGeSNDpW+JB3+aKanYb4UETJOF1/CxGPemA==} + engines: {node: '>=12.22.0'} + dev: true + + /@pnpm/network.ca-file/1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + dependencies: + graceful-fs: 4.2.10 + dev: true + + /@pnpm/npm-conf/2.1.0: + resolution: {integrity: sha512-Oe6ntvgsMTE3hDIqy6sajqHF+MnzJrOF06qC2QSiUEybLL7cp6tjoKUa32gpd9+KPVl4QyMs3E3nsXrx/Vdnlw==} + engines: {node: '>=12'} + dependencies: + '@pnpm/config.env-replace': 1.0.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + dev: true + + /@semantic-release/changelog/6.0.2_semantic-release@19.0.5: + resolution: {integrity: sha512-jHqfTkoPbDEOAgAP18mGP53IxeMwxTISN+GwTRy9uLu58UjARoZU8ScCgWGeO2WPkEsm57H8AkyY02W2ntIlIw==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + fs-extra: 11.1.0 + lodash: 4.17.21 + semantic-release: 19.0.5 + dev: true + + /@semantic-release/commit-analyzer/9.0.2_semantic-release@19.0.5: + resolution: {integrity: sha512-E+dr6L+xIHZkX4zNMe6Rnwg4YQrWNXK+rNsvwOPpdFppvZO1olE2fIgWhv89TkQErygevbjsZFSIxp+u6w2e5g==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + dependencies: + conventional-changelog-angular: 5.0.13 + conventional-commits-filter: 2.0.7 + conventional-commits-parser: 3.2.4 + debug: 4.3.4 + import-from: 4.0.0 + lodash: 4.17.21 + micromatch: 4.0.5 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@semantic-release/error/3.0.0: + resolution: {integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==} + engines: {node: '>=14.17'} + dev: true + + /@semantic-release/git/10.0.1_semantic-release@19.0.5: + resolution: {integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + debug: 4.3.4 + dir-glob: 3.0.1 + execa: 5.1.1 + lodash: 4.17.21 + micromatch: 4.0.5 + p-reduce: 2.1.0 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@semantic-release/github/8.0.7_semantic-release@19.0.5: + resolution: {integrity: sha512-VtgicRIKGvmTHwm//iqTh/5NGQwsncOMR5vQK9pMT92Aem7dv37JFKKRuulUsAnUOIlO4G8wH3gPiBAA0iW0ww==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + dependencies: + '@octokit/rest': 19.0.7 + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + bottleneck: 2.19.5 + debug: 4.3.4 + dir-glob: 3.0.1 + fs-extra: 11.1.0 + globby: 11.1.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + issue-parser: 6.0.0 + lodash: 4.17.21 + mime: 3.0.0 + p-filter: 2.1.0 + p-retry: 4.6.2 + semantic-release: 19.0.5 + url-join: 4.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /@semantic-release/npm/9.0.2_semantic-release@19.0.5: + resolution: {integrity: sha512-zgsynF6McdzxPnFet+a4iO9HpAlARXOM5adz7VGVCvj0ne8wtL2ZOQoDV2wZPDmdEotDIbVeJjafhelZjs9j6g==} + engines: {node: '>=16 || ^14.17'} + peerDependencies: + semantic-release: '>=19.0.0' + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + execa: 5.1.1 + fs-extra: 11.1.0 + lodash: 4.17.21 + nerf-dart: 1.0.0 + normalize-url: 6.1.0 + npm: 8.19.4 + rc: 1.2.8 + read-pkg: 5.2.0 + registry-auth-token: 5.0.2 + semantic-release: 19.0.5 + semver: 7.3.8 + tempy: 1.0.1 + dev: true + + /@semantic-release/release-notes-generator/10.0.3_semantic-release@19.0.5: + resolution: {integrity: sha512-k4x4VhIKneOWoBGHkx0qZogNjCldLPRiAjnIpMnlUh6PtaWXp/T+C9U7/TaNDDtgDa5HMbHl4WlREdxHio6/3w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0-beta.1' + dependencies: + conventional-changelog-angular: 5.0.13 + conventional-changelog-writer: 5.0.1 + conventional-commits-filter: 2.0.7 + conventional-commits-parser: 3.2.4 + debug: 4.3.4 + get-stream: 6.0.1 + import-from: 4.0.0 + into-stream: 6.0.0 + lodash: 4.17.21 + read-pkg-up: 7.0.1 + semantic-release: 19.0.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@tootallnate/once/2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: true + + /@types/chai-subset/1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + dependencies: + '@types/chai': 4.3.4 + dev: true + + /@types/chai/4.3.4: + resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} + dev: true + + /@types/debug/4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 + dev: true + + /@types/elementtree/0.1.1: + resolution: {integrity: sha512-93gHOm+uRflYNtP9Bd/NBu+yWloeL4/8HdCy33nDVwfJFjCxZQuXfkYopXszW90pFSHI2XkimnQ0jvf3SvcHbw==} + dev: true + + /@types/fs-extra/8.1.2: + resolution: {integrity: sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==} + dependencies: + '@types/node': 18.15.0 + dev: true + + /@types/ini/1.3.31: + resolution: {integrity: sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==} + dev: true + + /@types/istanbul-lib-coverage/2.0.4: + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: true + + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + + /@types/json5/0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/mdast/3.0.10: + resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} + dependencies: + '@types/unist': 2.0.6 + dev: true + + /@types/minimist/1.2.2: + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + dev: true + + /@types/ms/0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: true + + /@types/node/18.15.0: + resolution: {integrity: sha512-z6nr0TTEOBGkzLGmbypWOGnpSpSIBorEhC4L+4HeQ2iezKCi4f77kyslRwvHeNitymGQ+oFyIWGP96l/DPSV9w==} + dev: true + + /@types/normalize-package-data/2.4.1: + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + dev: true + + /@types/parse-json/4.0.0: + resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: true + + /@types/plist/3.0.2: + resolution: {integrity: sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==} + dependencies: + '@types/node': 18.15.0 + xmlbuilder: 15.1.1 + dev: true + + /@types/retry/0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: true + + /@types/semver/7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + dev: true + + /@types/slice-ansi/4.0.0: + resolution: {integrity: sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==} + dev: true + + /@types/split2/3.2.1: + resolution: {integrity: sha512-7uz3yU+LooBq4yNOzlZD9PU9/1Eu0rTD1MjQ6apOVEoHsPrMUrFw7W8XrvWtesm2vK67SBK9AyJcOXtMpl9bgQ==} + dependencies: + '@types/node': 18.15.0 + dev: true + + /@types/through2/2.0.38: + resolution: {integrity: sha512-YFu+nHmjxMurkH1BSzA0Z1WrKDAY8jUKPZctNQn7mc+/KKtp2XxnclHFXxdB1m7Iqnzb5aywgP8TMK283LezGQ==} + dependencies: + '@types/node': 18.15.0 + dev: true + + /@types/unist/2.0.6: + resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + dev: true + + /@types/yauzl/2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} + dependencies: + '@types/node': 18.15.0 + dev: true + + /@typescript-eslint/eslint-plugin/4.33.0_7anazn7gl5tnln7tyojcuhgrj4: + resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + '@typescript-eslint/parser': ^4.0.0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/experimental-utils': 4.33.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/parser': 4.33.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/scope-manager': 4.33.0 + debug: 4.3.4 + eslint: 8.35.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.4 + regexpp: 3.2.0 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin/5.54.0_6mj2wypvdnknez7kws2nfdgupi: + resolution: {integrity: sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/type-utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + debug: 4.3.4 + eslint: 8.35.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + regexpp: 3.2.0 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/experimental-utils/4.33.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: '*' + dependencies: + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.9.5 + eslint: 8.35.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.35.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/parser/4.33.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.9.5 + debug: 4.3.4 + eslint: 8.35.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 + debug: 4.3.4 + eslint: 8.35.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager/4.33.0: + resolution: {integrity: sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + dependencies: + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/visitor-keys': 4.33.0 + dev: true + + /@typescript-eslint/scope-manager/5.54.0: + resolution: {integrity: sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 + dev: true + + /@typescript-eslint/type-utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + debug: 4.3.4 + eslint: 8.35.0 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types/4.33.0: + resolution: {integrity: sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + dev: true + + /@typescript-eslint/types/5.54.0: + resolution: {integrity: sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree/4.33.0_typescript@4.9.5: + resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/visitor-keys': 4.33.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree/5.54.0_typescript@4.9.5: + resolution: {integrity: sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 + eslint: 8.35.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.35.0 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys/4.33.0: + resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + dependencies: + '@typescript-eslint/types': 4.33.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /@typescript-eslint/visitor-keys/5.54.0: + resolution: {integrity: sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.54.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@vitest/coverage-c8/0.29.2_vitest@0.29.2: + resolution: {integrity: sha512-NmD3WirQCeQjjKfHu4iEq18DVOBFbLn9TKVdMpyi5YW2EtnS+K22/WE+9/wRrepOhyeTxuEFgxUVkCAE1GhbnQ==} + peerDependencies: + vitest: '>=0.29.0 <1' + dependencies: + c8: 7.13.0 + picocolors: 1.0.0 + std-env: 3.3.2 + vitest: 0.29.2 + dev: true + + /@vitest/expect/0.29.2: + resolution: {integrity: sha512-wjrdHB2ANTch3XKRhjWZN0UueFocH0cQbi2tR5Jtq60Nb3YOSmakjdAvUa2JFBu/o8Vjhj5cYbcMXkZxn1NzmA==} + dependencies: + '@vitest/spy': 0.29.2 + '@vitest/utils': 0.29.2 + chai: 4.3.7 + dev: true + + /@vitest/runner/0.29.2: + resolution: {integrity: sha512-A1P65f5+6ru36AyHWORhuQBJrOOcmDuhzl5RsaMNFe2jEkoj0faEszQS4CtPU/LxUYVIazlUtZTY0OEZmyZBnA==} + dependencies: + '@vitest/utils': 0.29.2 + p-limit: 4.0.0 + pathe: 1.1.0 + dev: true + + /@vitest/spy/0.29.2: + resolution: {integrity: sha512-Hc44ft5kaAytlGL2PyFwdAsufjbdOvHklwjNy/gy/saRbg9Kfkxfh+PklLm1H2Ib/p586RkQeNFKYuJInUssyw==} + dependencies: + tinyspy: 1.1.1 + dev: true + + /@vitest/utils/0.29.2: + resolution: {integrity: sha512-F14/Uc+vCdclStS2KEoXJlOLAEyqRhnw0gM27iXw9bMTcyKRPJrQ+rlC6XZ125GIPvvKYMPpVxNhiou6PsEeYQ==} + dependencies: + cli-truncate: 3.1.0 + diff: 5.1.0 + loupe: 2.3.6 + picocolors: 1.0.0 + pretty-format: 27.5.1 + dev: true + + /JSONStream/1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: true + + /acorn-jsx/5.3.2_acorn@8.8.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.2 + dev: true + + /acorn-walk/8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn/8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /agent-base/6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /aggregate-error/3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /ajv/6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-escapes/5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex/6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles/5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /ansi-styles/6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /ansicolors/0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + dev: true + + /any-promise/1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /argv-formatter/1.0.0: + resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} + dev: true + + /array-ify/1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + dev: true + + /array-includes/3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + get-intrinsic: 1.2.0 + is-string: 1.0.7 + dev: true + + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.flat/1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + es-shim-unscopables: 1.0.0 + dev: true + + /array.prototype.flatmap/1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + es-shim-unscopables: 1.0.0 + dev: true + + /arrify/1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: true + + /assertion-error/1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + + /astral-regex/2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /at-least-node/1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /available-typed-arrays/1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /before-after-hook/2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: true + + /big-integer/1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: true + + /binary-extensions/2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /boolbase/1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /bottleneck/2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + dev: true + + /bplist-parser/0.3.2: + resolution: {integrity: sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.51 + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces/3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer-crc32/0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + + /builtin-modules/3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + + /builtins/5.0.1: + resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + dependencies: + semver: 7.3.8 + dev: true + + /bumpp/9.0.0: + resolution: {integrity: sha512-I2+JLFQin46NioHg6wi23hYQMVExiJyGblARp5fIHUzLv3rRz9me38eUe2xlQCAl7Ys9X+SlhTaIkttTxiL6cQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jsdevtools/ez-spawn': 3.0.4 + cac: 6.7.14 + fast-glob: 3.2.12 + prompts: 2.4.2 + semver: 7.3.8 + dev: true + + /bundle-require/4.0.1_esbuild@0.17.11: + resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.17.11 + load-tsconfig: 0.2.3 + dev: true + + /c8/7.13.0: + resolution: {integrity: sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==} + engines: {node: '>=10.12.0'} + hasBin: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-report: 3.0.0 + istanbul-reports: 3.1.5 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 9.1.0 + yargs: 16.2.0 + yargs-parser: 20.2.9 + dev: true + + /cac/6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + + /call-bind/1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.0 + dev: true + + /call-me-maybe/1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + dev: true + + /callsites/3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-keys/6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: true + + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /cardinal/2.1.1: + resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} + hasBin: true + dependencies: + ansicolors: 0.3.2 + redeyed: 2.1.1 + dev: true + + /chai/4.3.7: + resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 4.1.3 + get-func-name: 2.0.0 + loupe: 2.3.6 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk/5.2.0: + resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /character-entities-legacy/1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + dev: true + + /character-entities/1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + dev: true + + /character-reference-invalid/1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + dev: true + + /check-error/1.0.2: + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + dev: true + + /chokidar/3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /ci-info/3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + dev: true + + /clean-regexp/1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /clean-stack/2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /cli-table3/0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + + /cli-truncate/3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name/1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /commander/4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /compare-func/2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /config-chain/1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: true + + /conventional-changelog-angular/5.0.13: + resolution: {integrity: sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + q: 1.5.1 + dev: true + + /conventional-changelog-writer/5.0.1: + resolution: {integrity: sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + conventional-commits-filter: 2.0.7 + dateformat: 3.0.3 + handlebars: 4.7.7 + json-stringify-safe: 5.0.1 + lodash: 4.17.21 + meow: 8.1.2 + semver: 6.3.0 + split: 1.0.1 + through2: 4.0.2 + dev: true + + /conventional-commits-filter/2.0.7: + resolution: {integrity: sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==} + engines: {node: '>=10'} + dependencies: + lodash.ismatch: 4.4.0 + modify-values: 1.0.1 + dev: true + + /conventional-commits-parser/3.2.4: + resolution: {integrity: sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==} + engines: {node: '>=10'} + hasBin: true + dependencies: + JSONStream: 1.3.5 + is-text-path: 1.0.1 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + dev: true + + /convert-source-map/1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: true + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /cosmiconfig/7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.0 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /cross-spawn/7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /crypto-random-string/2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + dev: true + + /cssesc/3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /dateformat/3.0.3: + resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} + dev: true + + /debug/3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /debug/4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /decamelize-keys/1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: true + + /decamelize/1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: true + + /deep-eql/4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 + dev: true + + /deep-extend/0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: true + + /deep-is/0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /define-properties/1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + + /del/6.1.1: + resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} + engines: {node: '>=10'} + dependencies: + globby: 11.1.0 + graceful-fs: 4.2.10 + is-glob: 4.0.3 + is-path-cwd: 2.2.0 + is-path-inside: 3.0.3 + p-map: 4.0.0 + rimraf: 3.0.2 + slash: 3.0.0 + dev: true + + /deprecation/2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: true + + /diff/5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine/2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + dev: true + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils/3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: true + + /dot-prop/5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + dev: true + + /duplexer2/0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + dependencies: + readable-stream: 2.3.8 + dev: true + + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /elementtree/0.1.7: + resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==} + engines: {node: '>= 0.4.0'} + dependencies: + sax: 1.1.4 + dev: true + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /entities/4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + dev: true + + /env-ci/5.5.0: + resolution: {integrity: sha512-o0JdWIbOLP+WJKIUt36hz1ImQQFuN92nhsfTkHHap+J8CiI8WgGpH/a9jEGHh4/TU5BUUGjlnKXNoDb57+ne+A==} + engines: {node: '>=10.17'} + dependencies: + execa: 5.1.1 + fromentries: 1.3.2 + java-properties: 1.0.2 + dev: true + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-abstract/1.21.1: + resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.0 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.10 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.9 + dev: true + + /es-set-tostringtag/2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.0 + has: 1.0.3 + has-tostringtag: 1.0.0 + dev: true + + /es-shim-unscopables/1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + dependencies: + has: 1.0.3 + dev: true + + /es-to-primitive/1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild/0.16.17: + resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.16.17 + '@esbuild/android-arm64': 0.16.17 + '@esbuild/android-x64': 0.16.17 + '@esbuild/darwin-arm64': 0.16.17 + '@esbuild/darwin-x64': 0.16.17 + '@esbuild/freebsd-arm64': 0.16.17 + '@esbuild/freebsd-x64': 0.16.17 + '@esbuild/linux-arm': 0.16.17 + '@esbuild/linux-arm64': 0.16.17 + '@esbuild/linux-ia32': 0.16.17 + '@esbuild/linux-loong64': 0.16.17 + '@esbuild/linux-mips64el': 0.16.17 + '@esbuild/linux-ppc64': 0.16.17 + '@esbuild/linux-riscv64': 0.16.17 + '@esbuild/linux-s390x': 0.16.17 + '@esbuild/linux-x64': 0.16.17 + '@esbuild/netbsd-x64': 0.16.17 + '@esbuild/openbsd-x64': 0.16.17 + '@esbuild/sunos-x64': 0.16.17 + '@esbuild/win32-arm64': 0.16.17 + '@esbuild/win32-ia32': 0.16.17 + '@esbuild/win32-x64': 0.16.17 + dev: true + + /esbuild/0.17.11: + resolution: {integrity: sha512-pAMImyokbWDtnA/ufPxjQg0fYo2DDuzAlqwnDvbXqHLphe+m80eF++perYKVm8LeTuj2zUuFXC+xgSVxyoHUdg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.11 + '@esbuild/android-arm64': 0.17.11 + '@esbuild/android-x64': 0.17.11 + '@esbuild/darwin-arm64': 0.17.11 + '@esbuild/darwin-x64': 0.17.11 + '@esbuild/freebsd-arm64': 0.17.11 + '@esbuild/freebsd-x64': 0.17.11 + '@esbuild/linux-arm': 0.17.11 + '@esbuild/linux-arm64': 0.17.11 + '@esbuild/linux-ia32': 0.17.11 + '@esbuild/linux-loong64': 0.17.11 + '@esbuild/linux-mips64el': 0.17.11 + '@esbuild/linux-ppc64': 0.17.11 + '@esbuild/linux-riscv64': 0.17.11 + '@esbuild/linux-s390x': 0.17.11 + '@esbuild/linux-x64': 0.17.11 + '@esbuild/netbsd-x64': 0.17.11 + '@esbuild/openbsd-x64': 0.17.11 + '@esbuild/sunos-x64': 0.17.11 + '@esbuild/win32-arm64': 0.17.11 + '@esbuild/win32-ia32': 0.17.11 + '@esbuild/win32-x64': 0.17.11 + dev: true + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier/6.15.0_eslint@8.35.0: + resolution: {integrity: sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==} + hasBin: true + peerDependencies: + eslint: '>=3.14.1' + dependencies: + eslint: 8.35.0 + get-stdin: 6.0.0 + dev: true + + /eslint-import-resolver-node/0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + dependencies: + debug: 3.2.7 + is-core-module: 2.11.0 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils/2.7.4_lzarrkt6246mjajqnc4rgpupcq: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 4.33.0_ycpbpc6yetojsgtrx3mwntkhsu + debug: 3.2.7 + eslint: 8.35.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils/2.7.4_qynxowrxvm2kj5rbowcxf5maga: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + debug: 3.2.7 + eslint: 8.35.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-antfu/0.36.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-qLYtjZC2y6d1fvVtG4nvVGoBUDEuUwQsS4E1RwjoEZyONZAkHYDPfeoeULDlPS0IqumSW8uGR6zGSAXi5rrVMg==} + dependencies: + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + transitivePeerDependencies: + - eslint + - supports-color + - typescript + dev: true + + /eslint-plugin-es/4.1.0_eslint@8.35.0: + resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + eslint: 8.35.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 + dev: true + + /eslint-plugin-eslint-comments/3.2.0_eslint@8.35.0: + resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} + engines: {node: '>=6.5.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + escape-string-regexp: 1.0.5 + eslint: 8.35.0 + ignore: 5.2.4 + dev: true + + /eslint-plugin-html/7.1.0: + resolution: {integrity: sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==} + dependencies: + htmlparser2: 8.0.1 + dev: true + + /eslint-plugin-import/2.27.5_ajyizmi44oc3hrc35l6ndh7p4e: + resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.35.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4_qynxowrxvm2kj5rbowcxf5maga + has: 1.0.3 + is-core-module: 2.11.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.6 + resolve: 1.22.1 + semver: 6.3.0 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-import/2.27.5_menevh4pffsl3d4xx5zxnod25u: + resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 4.33.0_ycpbpc6yetojsgtrx3mwntkhsu + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.35.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4_lzarrkt6246mjajqnc4rgpupcq + has: 1.0.3 + is-core-module: 2.11.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.6 + resolve: 1.22.1 + semver: 6.3.0 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-jest/27.2.1_aere4n7c7ynvp62ae3ihfxuwhu: + resolution: {integrity: sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^7.0.0 || ^8.0.0 + jest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + eslint: 8.35.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /eslint-plugin-jsonc/2.6.0_eslint@8.35.0: + resolution: {integrity: sha512-4bA9YTx58QaWalua1Q1b82zt7eZMB7i+ed8q8cKkbKP75ofOA2SXbtFyCSok7RY6jIXeCqQnKjN9If8zCgv6PA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + eslint: 8.35.0 + eslint-utils: 3.0.0_eslint@8.35.0 + jsonc-eslint-parser: 2.1.0 + natural-compare: 1.4.0 + dev: true + + /eslint-plugin-markdown/3.0.0_eslint@8.35.0: + resolution: {integrity: sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.35.0 + mdast-util-from-markdown: 0.8.5 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-n/15.6.1_eslint@8.35.0: + resolution: {integrity: sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==} + engines: {node: '>=12.22.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + builtins: 5.0.1 + eslint: 8.35.0 + eslint-plugin-es: 4.1.0_eslint@8.35.0 + eslint-utils: 3.0.0_eslint@8.35.0 + ignore: 5.2.4 + is-core-module: 2.11.0 + minimatch: 3.1.2 + resolve: 1.22.1 + semver: 7.3.8 + dev: true + + /eslint-plugin-no-only-tests/3.1.0: + resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==} + engines: {node: '>=5.0.0'} + dev: true + + /eslint-plugin-promise/6.1.1_eslint@8.35.0: + resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.35.0 + dev: true + + /eslint-plugin-unicorn/45.0.2_eslint@8.35.0: + resolution: {integrity: sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==} + engines: {node: '>=14.18'} + peerDependencies: + eslint: '>=8.28.0' + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + '@eslint-community/eslint-utils': 4.2.0_eslint@8.35.0 + ci-info: 3.8.0 + clean-regexp: 1.0.0 + eslint: 8.35.0 + esquery: 1.5.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.1 + jsesc: 3.0.2 + lodash: 4.17.21 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.24 + regjsparser: 0.9.1 + safe-regex: 2.1.1 + semver: 7.3.8 + strip-indent: 3.0.0 + dev: true + + /eslint-plugin-unused-imports/2.0.0_hlu2tevvfejtijvruutuci6rky: + resolution: {integrity: sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi + eslint: 8.35.0 + eslint-rule-composer: 0.3.0 + dev: true + + /eslint-plugin-vue/9.9.0_eslint@8.35.0: + resolution: {integrity: sha512-YbubS7eK0J7DCf0U2LxvVP7LMfs6rC6UltihIgval3azO3gyDwEGVgsCMe1TmDiEkl6GdMKfRpaME6QxIYtzDQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.35.0 + eslint-utils: 3.0.0_eslint@8.35.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.11 + semver: 7.3.8 + vue-eslint-parser: 9.1.0_eslint@8.35.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-yml/1.5.0_eslint@8.35.0: + resolution: {integrity: sha512-iygN054g+ZrnYmtOXMnT+sx9iDNXt89/m0+506cQHeG0+5jJN8hY5iOPQLd3yfd50AfK/mSasajBWruf1SoHpQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.35.0 + lodash: 4.17.21 + natural-compare: 1.4.0 + yaml-eslint-parser: 1.1.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-rule-composer/0.3.0: + resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} + engines: {node: '>=4.0.0'} + dev: true + + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils/2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + dependencies: + eslint-visitor-keys: 1.3.0 + dev: true + + /eslint-utils/3.0.0_eslint@8.35.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.35.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys/1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + dev: true + + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint/8.35.0: + resolution: {integrity: sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 2.0.0 + '@eslint/js': 8.35.0 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.35.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.20.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.3.0 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.2 + acorn-jsx: 5.3.2_acorn@8.8.2 + eslint-visitor-keys: 3.3.0 + dev: true + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery/1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse/4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /execa/5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob/3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify/2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein/2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq/1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fd-slicer/1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + + /figures/2.0.0: + resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} + engines: {node: '>=4'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /figures/3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + + /fill-range/7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up/2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + dependencies: + locate-path: 2.0.0 + dev: true + + /find-up/4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /find-versions/4.0.0: + resolution: {integrity: sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==} + engines: {node: '>=10'} + dependencies: + semver-regex: 3.1.4 + dev: true + + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /for-each/0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /foreground-child/2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + dev: true + + /from2/2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + dev: true + + /fromentries/1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + dev: true + + /fs-extra/11.1.0: + resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs-extra/9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /function.prototype.name/1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + functions-have-names: 1.2.3 + dev: true + + /functional-red-black-tree/1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + dev: true + + /functions-have-names/1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-func-name/2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + dev: true + + /get-intrinsic/1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + dev: true + + /get-stdin/6.0.0: + resolution: {integrity: sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==} + engines: {node: '>=4'} + dev: true + + /get-stream/6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-symbol-description/1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + dev: true + + /git-log-parser/1.2.0: + resolution: {integrity: sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==} + dependencies: + argv-formatter: 1.0.0 + spawn-error-forwarder: 1.0.0 + split2: 1.0.0 + stream-combiner2: 1.1.1 + through2: 2.0.5 + traverse: 0.6.7 + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob/7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals/13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis/1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.0 + dev: true + + /globby/11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd/1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.0 + dev: true + + /graceful-fs/4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + dev: true + + /grapheme-splitter/1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /handlebars/4.7.7: + resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} + engines: {node: '>=0.4.7'} + hasBin: true + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + dev: true + + /hard-rejection/2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: true + + /has-bigints/1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag/3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-property-descriptors/1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.2.0 + dev: true + + /has-proto/1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols/1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag/1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /hook-std/2.0.0: + resolution: {integrity: sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==} + engines: {node: '>=8'} + dev: true + + /hosted-git-info/2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /hosted-git-info/4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: true + + /html-escaper/2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /htmlparser2/8.0.1: + resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + entities: 4.4.0 + dev: true + + /http-proxy-agent/5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent/5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /human-signals/2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /husky/5.2.0: + resolution: {integrity: sha512-AM8T/auHXRBxlrfPVLKP6jt49GCM2Zz47m8G3FOMsLmTv8Dj/fKVWE0Rh2d4Qrvmy131xEsdQnb3OXRib67PGg==} + engines: {node: '>= 10'} + hasBin: true + dev: true + + /ignore/5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-from/4.0.0: + resolution: {integrity: sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==} + engines: {node: '>=12.2'} + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /ini/3.0.1: + resolution: {integrity: sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dev: true + + /internal-slot/1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.0 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + + /into-stream/6.0.0: + resolution: {integrity: sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==} + engines: {node: '>=10'} + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 + dev: true + + /is-alphabetical/1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + dev: true + + /is-alphanumerical/1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + dev: true + + /is-array-buffer/3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + is-typed-array: 1.1.10 + dev: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-bigint/1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path/2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-boolean-object/1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + + /is-builtin-module/3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-callable/1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module/2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + dependencies: + has: 1.0.3 + dev: true + + /is-date-object/1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-decimal/1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-fullwidth-code-point/4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-hexadecimal/1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + dev: true + + /is-negative-zero/2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object/1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-obj/2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: true + + /is-path-cwd/2.2.0: + resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} + engines: {node: '>=6'} + dev: true + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-obj/1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: true + + /is-plain-object/5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-regex/1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + + /is-shared-array-buffer/1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-stream/2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-string/1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol/1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-text-path/1.0.1: + resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} + engines: {node: '>=0.10.0'} + dependencies: + text-extensions: 1.9.0 + dev: true + + /is-typed-array/1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /is-weakref/1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.2 + dev: true + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /issue-parser/6.0.0: + resolution: {integrity: sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==} + engines: {node: '>=10.13'} + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + dev: true + + /istanbul-lib-coverage/3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + supports-color: 7.2.0 + dev: true + + /istanbul-reports/3.1.5: + resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + + /java-properties/1.0.2: + resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} + engines: {node: '>= 0.6.0'} + dev: true + + /joycon/3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + + /js-sdsl/4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc/0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + + /jsesc/3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /json-parse-better-errors/1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + dev: true + + /json-parse-even-better-errors/2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse/0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json-stringify-safe/5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: true + + /json5/1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /jsonc-eslint-parser/2.1.0: + resolution: {integrity: sha512-qCRJWlbP2v6HbmKW7R3lFbeiVWHo+oMJ0j+MizwvauqnCV/EvtAeEeuCgoc/ErtsuoKgYB8U4Ih8AxJbXoE6/g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.2 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + semver: 7.3.8 + dev: true + + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.10 + dev: true + + /jsonparse/1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: true + + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + + /kleur/3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lilconfig/2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lines-and-columns/1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /load-json-file/4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + dependencies: + graceful-fs: 4.2.10 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + dev: true + + /load-tsconfig/0.2.3: + resolution: {integrity: sha512-iyT2MXws+dc2Wi6o3grCFtGXpeMvHmJqS27sMPGtV2eUu4PeFnG+33I8BlFK1t1NWMjOpcx9bridn5yxLDX2gQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /local-pkg/0.4.3: + resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + engines: {node: '>=14'} + dev: true + + /locate-path/2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + dev: true + + /locate-path/5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.capitalize/4.2.1: + resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} + dev: true + + /lodash.escaperegexp/4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + dev: true + + /lodash.ismatch/4.4.0: + resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} + dev: true + + /lodash.isplainobject/4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + + /lodash.isstring/4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + dev: true + + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash.sortby/4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: true + + /lodash.uniqby/4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + dev: true + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /loupe/2.3.6: + resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + dependencies: + get-func-name: 2.0.0 + dev: true + + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /make-dir/3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /map-obj/1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: true + + /map-obj/4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: true + + /marked-terminal/5.1.1_marked@4.2.12: + resolution: {integrity: sha512-+cKTOx9P4l7HwINYhzbrBSyzgxO2HaHKGZGuB1orZsMIgXYaJyfidT81VXRdpelW/PcHEWxywscePVgI/oUF6g==} + engines: {node: '>=14.13.1 || >=16.0.0'} + peerDependencies: + marked: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 + dependencies: + ansi-escapes: 5.0.0 + cardinal: 2.1.1 + chalk: 5.2.0 + cli-table3: 0.6.3 + marked: 4.2.12 + node-emoji: 1.11.0 + supports-hyperlinks: 2.3.0 + dev: true + + /marked/4.2.12: + resolution: {integrity: sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==} + engines: {node: '>= 12'} + hasBin: true + dev: true + + /mdast-util-from-markdown/0.8.5: + resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-string: 2.0.0 + micromark: 2.11.4 + parse-entities: 2.0.0 + unist-util-stringify-position: 2.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-to-string/2.0.0: + resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} + dev: true + + /meow/8.1.2: + resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} + engines: {node: '>=10'} + dependencies: + '@types/minimist': 1.2.2 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + dev: true + + /merge-stream/2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromark/2.11.4: + resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} + dependencies: + debug: 4.3.4 + parse-entities: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /micromatch/4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime/3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: true + + /mimic-fn/2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /min-indent/1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist-options/4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: true + + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /mlly/1.1.1: + resolution: {integrity: sha512-Jnlh4W/aI4GySPo6+DyTN17Q75KKbLTyFK8BrGhjNP4rxuUjbRWhE6gHg3bs33URWAF44FRm7gdQA348i3XxRw==} + dependencies: + acorn: 8.8.2 + pathe: 1.1.0 + pkg-types: 1.0.2 + ufo: 1.1.1 + dev: true + + /modify-values/1.0.1: + resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} + engines: {node: '>=0.10.0'} + dev: true + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /mz/2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nanoid/3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare-lite/1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /natural-compare/1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /neo-async/2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /nerf-dart/1.0.0: + resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} + dev: true + + /node-emoji/1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + dependencies: + lodash: 4.17.21 + dev: true + + /node-fetch/2.6.9: + resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /normalize-package-data/2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.1 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-package-data/3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.11.0 + semver: 7.3.8 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path/3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-url/6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + dev: true + + /npm-run-path/4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npm/8.19.4: + resolution: {integrity: sha512-3HANl8i9DKnUA89P4KEgVNN28EjSeDCmvEqbzOAuxCFDzdBZzjUl99zgnGpOUumvW5lvJo2HKcjrsc+tfyv1Hw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + dev: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/ci-detect' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/package-json' + - '@npmcli/run-script' + - abbrev + - archy + - cacache + - chalk + - chownr + - cli-columns + - cli-table3 + - columnify + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmhook + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - mkdirp + - mkdirp-infer-owner + - ms + - node-gyp + - nopt + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - npmlog + - opener + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - read-package-json + - read-package-json-fast + - readdir-scoped-modules + - rimraf + - semver + - ssri + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + - write-file-atomic + + /nth-check/2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect/1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + + /object-keys/1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign/4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.values/1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + dev: true + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime/5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + + /p-each-series/2.2.0: + resolution: {integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==} + engines: {node: '>=8'} + dev: true + + /p-filter/2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + dependencies: + p-map: 2.1.0 + dev: true + + /p-is-promise/3.0.0: + resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} + engines: {node: '>=8'} + dev: true + + /p-limit/1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + dependencies: + p-try: 1.0.0 + dev: true + + /p-limit/2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-limit/4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + + /p-locate/2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + dependencies: + p-limit: 1.3.0 + dev: true + + /p-locate/4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-map/2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + dev: true + + /p-map/4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-reduce/2.1.0: + resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==} + engines: {node: '>=8'} + dev: true + + /p-retry/4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + dev: true + + /p-try/1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + dev: true + + /p-try/2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-entities/2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + dev: true + + /parse-json/4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + dev: true + + /parse-json/5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.18.6 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-exists/3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + dev: true + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key/3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pathe/1.1.0: + resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} + dev: true + + /pathval/1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /pend/1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify/3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + dev: true + + /pirates/4.0.5: + resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} + engines: {node: '>= 6'} + dev: true + + /pkg-conf/2.1.0: + resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} + engines: {node: '>=4'} + dependencies: + find-up: 2.1.0 + load-json-file: 4.0.0 + dev: true + + /pkg-types/1.0.2: + resolution: {integrity: sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.1.1 + pathe: 1.1.0 + dev: true + + /plist/3.0.6: + resolution: {integrity: sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==} + engines: {node: '>=6'} + dependencies: + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + dev: true + + /pluralize/8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + dev: true + + /postcss-load-config/3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 1.10.2 + dev: true + + /postcss-selector-parser/6.0.11: + resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss/8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier/2.8.4: + resolution: {integrity: sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + + /pretty-format/27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + dev: true + + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /prompts/2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /proto-list/1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true + + /punycode/2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /q/1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-lru/4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + dev: true + + /rc/1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: true + + /react-is/17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: true + + /read-pkg-up/7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg/5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + + /readable-stream/2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readable-stream/3.6.1: + resolution: {integrity: sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /readdirp/3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /redent/3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: true + + /redeyed/2.1.1: + resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} + dependencies: + esprima: 4.0.1 + dev: true + + /regexp-tree/0.1.24: + resolution: {integrity: sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==} + hasBin: true + dev: true + + /regexp.prototype.flags/1.4.3: + resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + functions-have-names: 1.2.3 + dev: true + + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + + /registry-auth-token/5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} + dependencies: + '@pnpm/npm-conf': 2.1.0 + dev: true + + /regjsparser/0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: true + + /require-directory/2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from/5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve/1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /retry/0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.1.6 + dev: true + + /rollup/3.18.0: + resolution: {integrity: sha512-J8C6VfEBjkvYPESMQYxKHxNOh4A5a3FlP+0BETGo34HEcE4eTlgCrO2+eWzlu2a/sHs2QUkZco+wscH7jhhgWg==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safe-regex-test/1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + is-regex: 1.1.4 + dev: true + + /safe-regex/2.1.1: + resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} + dependencies: + regexp-tree: 0.1.24 + dev: true + + /sax/1.1.4: + resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==} + dev: true + + /semantic-release/19.0.5: + resolution: {integrity: sha512-NMPKdfpXTnPn49FDogMBi36SiBfXkSOJqCkk0E4iWOY1tusvvgBwqUmxTX1kmlT6kIYed9YwNKD1sfPpqa5yaA==} + engines: {node: '>=16 || ^14.17'} + hasBin: true + dependencies: + '@semantic-release/commit-analyzer': 9.0.2_semantic-release@19.0.5 + '@semantic-release/error': 3.0.0 + '@semantic-release/github': 8.0.7_semantic-release@19.0.5 + '@semantic-release/npm': 9.0.2_semantic-release@19.0.5 + '@semantic-release/release-notes-generator': 10.0.3_semantic-release@19.0.5 + aggregate-error: 3.1.0 + cosmiconfig: 7.1.0 + debug: 4.3.4 + env-ci: 5.5.0 + execa: 5.1.1 + figures: 3.2.0 + find-versions: 4.0.0 + get-stream: 6.0.1 + git-log-parser: 1.2.0 + hook-std: 2.0.0 + hosted-git-info: 4.1.0 + lodash: 4.17.21 + marked: 4.2.12 + marked-terminal: 5.1.1_marked@4.2.12 + micromatch: 4.0.5 + p-each-series: 2.2.0 + p-reduce: 2.1.0 + read-pkg-up: 7.0.1 + resolve-from: 5.0.0 + semver: 7.3.8 + semver-diff: 3.1.1 + signale: 1.4.0 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /semver-diff/3.1.1: + resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /semver-regex/3.1.4: + resolution: {integrity: sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==} + engines: {node: '>=8'} + dev: true + + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /shebang-command/2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex/3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel/1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + object-inspect: 1.12.3 + dev: true + + /siginfo/2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signale/1.4.0: + resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} + engines: {node: '>=6'} + dependencies: + chalk: 2.4.2 + figures: 2.0.0 + pkg-conf: 2.1.0 + dev: true + + /sisteransi/1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash/3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /slice-ansi/4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi/5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /source-map-js/1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: true + + /spawn-error-forwarder/1.0.0: + resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} + dev: true + + /spdx-correct/3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.12 + dev: true + + /spdx-exceptions/2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse/3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.12 + dev: true + + /spdx-license-ids/3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + dev: true + + /split/1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + dependencies: + through: 2.3.8 + dev: true + + /split2/1.0.0: + resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} + dependencies: + through2: 2.0.5 + dev: true + + /split2/3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.1 + dev: true + + /split2/4.1.0: + resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} + engines: {node: '>= 10.x'} + dev: true + + /stackback/0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + + /std-env/3.3.2: + resolution: {integrity: sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==} + dev: true + + /stream-combiner2/1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + dev: true + + /string-argv/0.3.1: + resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} + engines: {node: '>=0.6.19'} + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width/5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.0.1 + dev: true + + /string.prototype.trimend/1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + dev: true + + /string.prototype.trimstart/1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + dev: true + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi/7.0.1: + resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-bom/3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-final-newline/2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-indent/3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + + /strip-json-comments/2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: true + + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /strip-literal/1.0.1: + resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} + dependencies: + acorn: 8.8.2 + dev: true + + /sucrase/3.29.0: + resolution: {integrity: sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==} + engines: {node: '>=8'} + hasBin: true + dependencies: + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.5 + ts-interface-checker: 0.1.13 + dev: true + + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-hyperlinks/2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + + /supports-preserve-symlinks-flag/1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /temp-dir/2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + dev: true + + /tempy/1.0.1: + resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} + engines: {node: '>=10'} + dependencies: + del: 6.1.1 + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + dev: true + + /test-exclude/6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.1.6 + minimatch: 3.1.2 + dev: true + + /text-extensions/1.9.0: + resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} + engines: {node: '>=0.10'} + dev: true + + /text-table/0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /thenify-all/1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify/3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /through/2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /through2/2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + dev: true + + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.1 + dev: true + + /tinybench/2.4.0: + resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==} + dev: true + + /tinypool/0.3.1: + resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy/1.1.1: + resolution: {integrity: sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==} + engines: {node: '>=14.0.0'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tr46/0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + + /tr46/1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.0 + dev: true + + /traverse/0.6.7: + resolution: {integrity: sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==} + dev: true + + /tree-kill/1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + + /trim-newlines/3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: true + + /ts-interface-checker/0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /tsconfig-paths/3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib/2.5.0: + resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + dev: true + + /tsup/6.6.3_typescript@4.9.5: + resolution: {integrity: sha512-OLx/jFllYlVeZQ7sCHBuRVEQBBa1tFbouoc/gbYakyipjVQdWy/iQOvmExUA/ewap9iQ7tbJf9pW0PgcEFfJcQ==} + engines: {node: '>=14.18'} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: ^4.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.1_esbuild@0.17.11 + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.17.11 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 3.1.4 + resolve-from: 5.0.0 + rollup: 3.18.0 + source-map: 0.8.0-beta.0 + sucrase: 3.29.0 + tree-kill: 1.2.2 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + + /tsutils/3.21.0_typescript@4.9.5: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + dev: true + + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-detect/4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest/0.16.0: + resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: true + + /type-fest/0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /typed-array-length/1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.10 + dev: true + + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /ufo/1.1.1: + resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} + dev: true + + /uglify-js/3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /unbox-primitive/1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.2 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /unique-string/2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + dependencies: + crypto-random-string: 2.0.0 + dev: true + + /unist-util-stringify-position/2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + dependencies: + '@types/unist': 2.0.6 + dev: true + + /universal-user-agent/6.0.0: + resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} + dev: true + + /universalify/2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + + /untildify/4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /uri-js/4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /url-join/4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + dev: true + + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /v8-to-istanbul/9.1.0: + resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.17 + '@types/istanbul-lib-coverage': 2.0.4 + convert-source-map: 1.9.0 + dev: true + + /validate-npm-package-license/3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + dev: true + + /vite-node/0.29.2_@types+node@18.15.0: + resolution: {integrity: sha512-5oe1z6wzI3gkvc4yOBbDBbgpiWiApvuN4P55E8OI131JGrSuo4X3SOZrNmZYo4R8Zkze/dhi572blX0zc+6SdA==} + engines: {node: '>=v14.16.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.1.1 + pathe: 1.1.0 + picocolors: 1.0.0 + vite: 4.1.4_@types+node@18.15.0 + transitivePeerDependencies: + - '@types/node' + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite/4.1.4_@types+node@18.15.0: + resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.15.0 + esbuild: 0.16.17 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.18.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vitest/0.29.2: + resolution: {integrity: sha512-ydK9IGbAvoY8wkg29DQ4ivcVviCaUi3ivuPKfZEVddMTenFHUfB8EEDXQV8+RasEk1ACFLgMUqAaDuQ/Nk+mQA==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.4 + '@types/chai-subset': 1.3.3 + '@types/node': 18.15.0 + '@vitest/expect': 0.29.2 + '@vitest/runner': 0.29.2 + '@vitest/spy': 0.29.2 + '@vitest/utils': 0.29.2 + acorn: 8.8.2 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.7 + debug: 4.3.4 + local-pkg: 0.4.3 + pathe: 1.1.0 + picocolors: 1.0.0 + source-map: 0.6.1 + std-env: 3.3.2 + strip-literal: 1.0.1 + tinybench: 2.4.0 + tinypool: 0.3.1 + tinyspy: 1.1.1 + vite: 4.1.4_@types+node@18.15.0 + vite-node: 0.29.2_@types+node@18.15.0 + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vue-eslint-parser/9.1.0_eslint@8.35.0: + resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.35.0 + eslint-scope: 7.1.1 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + dev: true + + /webidl-conversions/3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /webidl-conversions/4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: true + + /whatwg-url/5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /whatwg-url/7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + + /which-boxed-primitive/1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-typed-array/1.1.9: + resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + is-typed-array: 1.1.10 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /why-is-node-running/2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + + /word-wrap/1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wordwrap/1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true + + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /xml-name-validator/4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: true + + /xmlbuilder/15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + dev: true + + /xtend/4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml-eslint-parser/1.1.0: + resolution: {integrity: sha512-b464Q1fYiX1oYx2kE8k4mEp6S9Prk+tfDsY/IPxQ0FCjEuj3AKko5Skf3/yQJeYTTDyjDE+aWIJemnv29HvEWQ==} + engines: {node: ^14.17.0 || >=16.0.0} + dependencies: + eslint-visitor-keys: 3.3.0 + lodash: 4.17.21 + yaml: 2.2.1 + dev: true + + /yaml/1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /yaml/2.2.1: + resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} + engines: {node: '>= 14'} + dev: true + + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /yauzl/2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /yocto-queue/1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..e859a5d --- /dev/null +++ b/renovate.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "rebaseWhen": "conflicted", + "schedule": [ + "before 6am on the first day of the month" + ], + "baseBranches": [ + "main" + ], + "rangeStrategy": "bump", + "ignoreDeps": [ + "node", + "pnpm" + ], + "packageRules": [ + { + "matchFiles": [ + "package.json" + ], + "matchUpdateTypes": [ + "patch", + "minor", + "major" + ], + "groupName": "root", + "groupSlug": "shared-root", + "labels": [ + "dependencies" + ], + "addLabels": [ + "dependencies" + ] + } + ] +} \ No newline at end of file diff --git a/src/android/help.ts b/src/android/help.ts index d8a7e5a..43595aa 100644 --- a/src/android/help.ts +++ b/src/android/help.ts @@ -28,8 +28,8 @@ const help = ` --target ........... Use a specific target --connect ............... Tie process to app process --forward ... Forward a port from device to host -`; +` export async function run(args: readonly string[]): Promise { - process.stdout.write(`${help}\n`); + process.stdout.write(`${help}\n`) } diff --git a/src/android/index.ts b/src/android/index.ts index 84d835a..6589865 100644 --- a/src/android/index.ts +++ b/src/android/index.ts @@ -1,23 +1,23 @@ -import type { Command } from '../'; +import type { Command } from '../' export async function run(args: readonly string[]): Promise { - let cmd: Command; + let cmd: Command if (args.includes('--help') || args.includes('-h')) { - cmd = await import('./help'); - return cmd.run(args); + cmd = await import('./help') + return cmd.run(args) } if (args.includes('--list')) { - cmd = await import('./list'); - return cmd.run(args); + cmd = await import('./list') + return cmd.run(args) } if (args.includes('--sdk-info')) { - cmd = await import('./sdk-info'); - return cmd.run(args); + cmd = await import('./sdk-info') + return cmd.run(args) } - cmd = await import('./run'); - await cmd.run(args); + cmd = await import('./run') + await cmd.run(args) } diff --git a/src/android/list.ts b/src/android/list.ts index 68011df..9a0a170 100644 --- a/src/android/list.ts +++ b/src/android/list.ts @@ -1,37 +1,39 @@ -import type { Exception } from '../errors'; -import type { Targets } from '../utils/list'; -import { formatTargets } from '../utils/list'; +import type { Exception } from '../errors' +import type { Targets } from '../utils/list' +import { formatTargets } from '../utils/list' -import { getDeviceTargets, getVirtualTargets } from './utils/list'; -import { getSDK } from './utils/sdk'; +import { getDeviceTargets, getVirtualTargets } from './utils/list' +import { getSDK } from './utils/sdk' export async function run(args: readonly string[]): Promise { - const targets = await list(args); - process.stdout.write(`\n${formatTargets(args, targets)}\n`); + const targets = await list(args) + process.stdout.write(`\n${formatTargets(args, targets)}\n`) } export async function list(args: readonly string[]): Promise { - const sdk = await getSDK(); + const sdk = await getSDK() - const errors: Exception[] = []; + const errors: Exception[] = [] const [devices, virtualDevices] = await Promise.all([ (async () => { try { - return await getDeviceTargets(sdk); - } catch (e) { - errors.push(e); - return []; + return await getDeviceTargets(sdk) + } + catch (e) { + errors.push(e) + return [] } })(), (async () => { try { - return await getVirtualTargets(sdk); - } catch (e) { - errors.push(e); - return []; + return await getVirtualTargets(sdk) + } + catch (e) { + errors.push(e) + return [] } })(), - ]); + ]) - return { devices, virtualDevices, errors }; + return { devices, virtualDevices, errors } } diff --git a/src/android/run.ts b/src/android/run.ts index c1ed105..74c3268 100644 --- a/src/android/run.ts +++ b/src/android/run.ts @@ -1,4 +1,4 @@ -import * as Debug from 'debug'; +import Debug from 'debug' import { AVDException, @@ -9,12 +9,12 @@ import { ERR_NO_TARGET, ERR_TARGET_NOT_FOUND, ERR_UNSUITABLE_API_INSTALLATION, -} from '../errors'; -import { getOptionValue, getOptionValues } from '../utils/cli'; -import { log } from '../utils/log'; -import { onBeforeExit } from '../utils/process'; +} from '../errors' +import { getOptionValue, getOptionValues } from '../utils/cli' +import { log } from '../utils/log' +import { onBeforeExit } from '../utils/process' -import type { Device, Ports } from './utils/adb'; +import type { Device, Ports } from './utils/adb' import { closeApp, forwardPorts, @@ -23,89 +23,88 @@ import { unforwardPorts, waitForBoot, waitForClose, -} from './utils/adb'; -import { getApkInfo } from './utils/apk'; -import { getInstalledAVDs } from './utils/avd'; +} from './utils/adb' +import { getApkInfo } from './utils/apk' +import { getInstalledAVDs } from './utils/avd' import { installApkToDevice, selectDeviceByTarget, selectHardwareDevice, selectVirtualDevice, -} from './utils/run'; -import type { SDK } from './utils/sdk'; -import { getSDK } from './utils/sdk'; +} from './utils/run' +import type { SDK } from './utils/sdk' +import { getSDK } from './utils/sdk' -const modulePrefix = 'native-run:android:run'; +const modulePrefix = 'native-run:android:run' export async function run(args: readonly string[]): Promise { - const sdk = await getSDK(); - const apkPath = getOptionValue(args, '--app'); - const forwardedPorts = getOptionValues(args, '--forward'); + const sdk = await getSDK() + const apkPath = getOptionValue(args, '--app') + const forwardedPorts = getOptionValues(args, '--forward') - const ports: Ports[] = []; + const ports: Ports[] = [] if (forwardedPorts && forwardedPorts.length > 0) { forwardedPorts.forEach((port: string) => { - const [device, host] = port.split(':'); + const [device, host] = port.split(':') if (!device || !host) { throw new CLIException( `Invalid --forward value "${port}": expecting , e.g. 8080:8080`, - ); + ) } - ports.push({ device, host }); - }); + ports.push({ device, host }) + }) } - if (!apkPath) { - throw new CLIException('--app is required', ERR_BAD_INPUT); - } + if (!apkPath) + throw new CLIException('--app is required', ERR_BAD_INPUT) - const device = await selectDevice(sdk, args); + const device = await selectDevice(sdk, args) log( `Selected ${device.type === 'hardware' ? 'hardware device' : 'emulator'} ${ device.serial }\n`, - ); + ) - const { appId, activityName } = await getApkInfo(apkPath); - await waitForBoot(sdk, device); + const { appId, activityName } = await getApkInfo(apkPath) + await waitForBoot(sdk, device) if (ports) { await Promise.all( ports.map(async (port: Ports) => { - await forwardPorts(sdk, device, port); - log(`Forwarded device port ${port.device} to host port ${port.host}\n`); + await forwardPorts(sdk, device, port) + log(`Forwarded device port ${port.device} to host port ${port.host}\n`) }), - ); + ) } - await installApkToDevice(sdk, device, apkPath, appId); + await installApkToDevice(sdk, device, apkPath, appId) - log(`Starting application activity ${appId}/${activityName}...\n`); - await startActivity(sdk, device, appId, activityName); + log(`Starting application activity ${appId}/${activityName}...\n`) + await startActivity(sdk, device, appId, activityName) - log(`Run Successful\n`); + log('Run Successful\n') onBeforeExit(async () => { if (ports) { await Promise.all( ports.map(async (port: Ports) => { - await unforwardPorts(sdk, device, port); + await unforwardPorts(sdk, device, port) }), - ); + ) } - }); + }) if (args.includes('--connect')) { onBeforeExit(async () => { - await closeApp(sdk, device, appId); - }); + await closeApp(sdk, device, appId) + }) - log(`Waiting for app to close...\n`); - await waitForClose(sdk, device, appId); + log('Waiting for app to close...\n') + await waitForClose(sdk, device, appId) } } @@ -113,61 +112,64 @@ export async function selectDevice( sdk: SDK, args: readonly string[], ): Promise { - const debug = Debug(`${modulePrefix}:${selectDevice.name}`); + const debug = Debug(`${modulePrefix}:${selectDevice.name}`) - const devices = await getDevices(sdk); - const avds = await getInstalledAVDs(sdk); + const devices = await getDevices(sdk) + const avds = await getInstalledAVDs(sdk) - const target = getOptionValue(args, '--target'); - const preferEmulator = args.includes('--virtual'); + const target = getOptionValue(args, '--target') + const preferEmulator = args.includes('--virtual') if (target) { - const targetDevice = await selectDeviceByTarget(sdk, devices, avds, target); + const targetDevice = await selectDeviceByTarget(sdk, devices, avds, target) if (targetDevice) { - return targetDevice; - } else { + return targetDevice + } + else { throw new AndroidRunException( `Target not found: ${target}`, ERR_TARGET_NOT_FOUND, - ); + ) } } if (!preferEmulator) { - const selectedDevice = await selectHardwareDevice(devices); + const selectedDevice = await selectHardwareDevice(devices) if (selectedDevice) { - return selectedDevice; - } else if (args.includes('--device')) { + return selectedDevice + } + else if (args.includes('--device')) { throw new AndroidRunException( - `No hardware devices found. Not attempting emulator because --device was specified.`, + 'No hardware devices found. Not attempting emulator because --device was specified.', ERR_NO_DEVICE, - ); - } else { - log('No hardware devices found, attempting emulator...\n'); + ) + } + else { + log('No hardware devices found, attempting emulator...\n') } } try { - return await selectVirtualDevice(sdk, devices, avds); - } catch (e) { - if (!(e instanceof AVDException)) { - throw e; - } + return await selectVirtualDevice(sdk, devices, avds) + } + catch (e) { + if (!(e instanceof AVDException)) + throw e - debug('Issue with AVDs: %s', e.message); + debug('Issue with AVDs: %s', e.message) if (e.code === ERR_UNSUITABLE_API_INSTALLATION) { throw new AndroidRunException( 'No targets devices/emulators available. Cannot create AVD because there is no suitable API installation. Use --sdk-info to reveal missing packages and other issues.', ERR_NO_TARGET, - ); + ) } } throw new AndroidRunException( 'No target devices/emulators available.', ERR_NO_TARGET, - ); + ) } diff --git a/src/android/sdk-info.ts b/src/android/sdk-info.ts index 86b2f74..216bf92 100644 --- a/src/android/sdk-info.ts +++ b/src/android/sdk-info.ts @@ -1,55 +1,55 @@ -import { stringify } from '../utils/json'; +import { stringify } from '../utils/json' -import type { SDKPackage } from './utils/sdk'; -import { findAllSDKPackages, getSDK } from './utils/sdk'; -import type { APILevel } from './utils/sdk/api'; -import { API_LEVEL_SCHEMAS, getAPILevels } from './utils/sdk/api'; +import type { SDKPackage } from './utils/sdk' +import { findAllSDKPackages, getSDK } from './utils/sdk' +import type { APILevel } from './utils/sdk/api' +import { API_LEVEL_SCHEMAS, getAPILevels } from './utils/sdk/api' -type Platform = Required; +type Platform = Required interface SDKInfo { - root: string; - avdHome?: string; - platforms: Platform[]; - tools: SDKPackage[]; + root: string + avdHome?: string + platforms: Platform[] + tools: SDKPackage[] } export async function run(args: readonly string[]): Promise { - const sdk = await getSDK(); - const packages = await findAllSDKPackages(sdk); - const apis = await getAPILevels(packages); - const platforms = apis.map(api => { - const schema = API_LEVEL_SCHEMAS.find(s => s.apiLevel === api.apiLevel); - return { ...api, missingPackages: schema ? schema.validate(packages) : [] }; - }); + const sdk = await getSDK() + const packages = await findAllSDKPackages(sdk) + const apis = await getAPILevels(packages) + const platforms = apis.map((api) => { + const schema = API_LEVEL_SCHEMAS.find(s => s.apiLevel === api.apiLevel) + return { ...api, missingPackages: schema ? schema.validate(packages) : [] } + }) const sdkinfo: SDKInfo = { root: sdk.root, avdHome: sdk.avdHome, platforms, tools: packages.filter(pkg => typeof pkg.apiLevel === 'undefined'), - }; + } if (args.includes('--json')) { - process.stdout.write(stringify(sdkinfo)); - return; + process.stdout.write(stringify(sdkinfo)) + return } - process.stdout.write(`${formatSDKInfo(sdkinfo)}\n\n`); + process.stdout.write(`${formatSDKInfo(sdkinfo)}\n\n`) } function formatSDKInfo(sdk: SDKInfo): string { return ` SDK Location: ${sdk.root} AVD Home${ - sdk.avdHome ? `: ${sdk.avdHome}` : ` (!): not found` + sdk.avdHome ? `: ${sdk.avdHome}` : ' (!): not found' } ${sdk.platforms.map(platform => `${formatPlatform(platform)}\n\n`).join('\n')} Tools: ${sdk.tools.map(tool => formatPackage(tool)).join('\n')} - `.trim(); + `.trim() } function formatPlatform(platform: Platform): string { @@ -57,23 +57,23 @@ function formatPlatform(platform: Platform): string { API Level: ${platform.apiLevel} Packages: ${platform.packages .map(p => formatPackage(p)) - .join('\n' + ' '.repeat(22))} + .join(`\n${' '.repeat(22)}`)} ${ platform.missingPackages.length > 0 ? `(!) Missing Packages: ${platform.missingPackages .map(p => formatPackage(p)) - .join('\n' + ' '.repeat(22))}` + .join(`\n${' '.repeat(22)}`)}` : '' } - `.trim(); + `.trim() } function formatPackage(p: { - name: string; - path: string; - version?: string | RegExp; + name: string + path: string + version?: string | RegExp }): string { return `${p.name} ${p.path} ${ typeof p.version === 'string' ? p.version : '' - }`; + }` } diff --git a/src/android/utils/adb.ts b/src/android/utils/adb.ts index 901bacf..67270a0 100644 --- a/src/android/utils/adb.ts +++ b/src/android/utils/adb.ts @@ -1,9 +1,9 @@ -import { spawn } from 'child_process'; -import * as Debug from 'debug'; -import * as os from 'os'; -import * as path from 'path'; -import * as split2 from 'split2'; -import * as through2 from 'through2'; +import { spawn } from 'node:child_process' +import * as os from 'node:os' +import * as path from 'node:path' +import Debug from 'debug' +import split2 from 'split2' +import through2 from 'through2' import { ADBException, @@ -13,36 +13,36 @@ import { ERR_NOT_ENOUGH_SPACE, ERR_NO_CERTIFICATES, ERR_VERSION_DOWNGRADE, -} from '../../errors'; -import { execFile } from '../../utils/process'; +} from '../../errors' +import { execFile } from '../../utils/process' -import type { SDK } from './sdk'; -import { getSDKPackage, supplementProcessEnv } from './sdk'; +import type { SDK } from './sdk' +import { getSDKPackage, supplementProcessEnv } from './sdk' -const modulePrefix = 'native-run:android:utils:adb'; +const modulePrefix = 'native-run:android:utils:adb' export interface Ports { - readonly device: string; - readonly host: string; + readonly device: string + readonly host: string } export interface DeviceProperties { - [key: string]: string | undefined; + [key: string]: string | undefined } export interface MappedDeviceProps { - manufacturer: string; - model: string; - product: string; - sdkVersion: string; + manufacturer: string + model: string + product: string + sdkVersion: string } export interface Device extends MappedDeviceProps { - serial: string; - state: string; // 'offline' | 'device' | 'no device' - type: 'emulator' | 'hardware'; - connection: 'usb' | 'tcpip' | null; - properties: DeviceProperties; + serial: string + state: string // 'offline' | 'device' | 'no device' + type: 'emulator' | 'hardware' + connection: 'usb' | 'tcpip' | null + properties: DeviceProperties } const ADB_GETPROP_MAP: ReadonlyMap = new Map< @@ -53,34 +53,33 @@ const ADB_GETPROP_MAP: ReadonlyMap = new Map< ['ro.product.model', 'model'], ['ro.product.name', 'product'], ['ro.build.version.sdk', 'sdkVersion'], -]); +]) export async function getDevices(sdk: SDK): Promise { - const debug = Debug(`${modulePrefix}:${getDevices.name}`); - const args = ['devices', '-l']; + const debug = Debug(`${modulePrefix}:${getDevices.name}`) + const args = ['devices', '-l'] - debug('Invoking adb with args: %O', args); - const stdout = await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + const stdout = await execAdb(sdk, args, { timeout: 5000 }) - const devices = parseAdbDevices(stdout); + const devices = parseAdbDevices(stdout) await Promise.all( - devices.map(async device => { - const properties = await getDeviceProperties(sdk, device); + devices.map(async (device) => { + const properties = await getDeviceProperties(sdk, device) for (const [prop, deviceProp] of ADB_GETPROP_MAP.entries()) { - const value = properties[prop]; + const value = properties[prop] - if (value) { - device[deviceProp] = value; - } + if (value) + device[deviceProp] = value } }), - ); + ) - debug('Found adb devices: %O', devices); + debug('Found adb devices: %O', devices) - return devices; + return devices } export async function getDeviceProperty( @@ -88,68 +87,67 @@ export async function getDeviceProperty( device: Device, property: string, ): Promise { - const debug = Debug(`${modulePrefix}:${getDeviceProperty.name}`); - const args = ['-s', device.serial, 'shell', 'getprop', property]; + const debug = Debug(`${modulePrefix}:${getDeviceProperty.name}`) + const args = ['-s', device.serial, 'shell', 'getprop', property] - debug('Invoking adb with args: %O', args); - const stdout = await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + const stdout = await execAdb(sdk, args, { timeout: 5000 }) - return stdout.trim(); + return stdout.trim() } export async function getDeviceProperties( sdk: SDK, device: Device, ): Promise { - const debug = Debug(`${modulePrefix}:${getDeviceProperties.name}`); - const args = ['-s', device.serial, 'shell', 'getprop']; + const debug = Debug(`${modulePrefix}:${getDeviceProperties.name}`) + const args = ['-s', device.serial, 'shell', 'getprop'] - debug('Invoking adb with args: %O', args); - const stdout = await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + const stdout = await execAdb(sdk, args, { timeout: 5000 }) - const re = /^\[([a-z0-9.]+)\]: \[(.*)\]$/; - const propAllowList = [...ADB_GETPROP_MAP.keys()]; - const properties: DeviceProperties = {}; + const re = /^\[([a-z0-9.]+)\]: \[(.*)\]$/ + const propAllowList = [...ADB_GETPROP_MAP.keys()] + const properties: DeviceProperties = {} for (const line of stdout.split(os.EOL)) { - const m = line.match(re); + const m = line.match(re) if (m) { - const [, key, value] = m; + const [, key, value] = m - if (propAllowList.includes(key)) { - properties[key] = value; - } + if (propAllowList.includes(key)) + properties[key] = value } } - return properties; + return properties } export async function waitForDevice(sdk: SDK, serial: string): Promise { - const debug = Debug(`${modulePrefix}:${waitForDevice.name}`); - const args = ['-s', serial, 'wait-for-any-device']; + const debug = Debug(`${modulePrefix}:${waitForDevice.name}`) + const args = ['-s', serial, 'wait-for-any-device'] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args) - debug('Device %s is connected to ADB!', serial); + debug('Device %s is connected to ADB!', serial) } export async function waitForBoot(sdk: SDK, device: Device): Promise { - const debug = Debug(`${modulePrefix}:${waitForBoot.name}`); + const debug = Debug(`${modulePrefix}:${waitForBoot.name}`) - return new Promise(resolve => { + return new Promise((resolve) => { const interval = setInterval(async () => { - const booted = await getDeviceProperty(sdk, device, 'dev.bootcomplete'); + const booted = await getDeviceProperty(sdk, device, 'dev.bootcomplete') if (booted) { - debug('Device %s is booted!', device.serial); - clearInterval(interval); - resolve(); + debug('Device %s is booted!', device.serial) + clearInterval(interval) + resolve() } - }, 100); - }); + }, 100) + }) } export async function waitForClose( @@ -157,26 +155,36 @@ export async function waitForClose( device: Device, app: string, ): Promise { - const debug = Debug(`${modulePrefix}:${waitForClose.name}`); - const args = ['-s', device.serial, 'shell', `ps | grep ${app}`]; + const debug = Debug(`${modulePrefix}:${waitForClose.name}`) + const args = ['-s', device.serial, 'shell', `ps | grep ${app}`] - return new Promise(resolve => { + return new Promise((resolve) => { const interval = setInterval(async () => { try { - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args); - } catch (e) { - debug('Error received from adb: %O', e); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args) + } + catch (e) { + debug('Error received from adb: %O', e) debug( 'App %s no longer found in process list for %s', app, device.serial, - ); - clearInterval(interval); - resolve(); + ) + clearInterval(interval) + resolve() } - }, 500); - }); + }, 500) + }) +} + +export enum ADBEvent { + IncompatibleUpdateFailure, // signatures do not match the previously installed version + NewerVersionOnDeviceFailure, // version of app on device is newer than the one being deployed + NewerSdkRequiredOnDeviceFailure, // device does not meet minSdkVersion requirement + NoCertificates, // no certificates in APK, likely due to improper signing config + NotEnoughSpace, // device is out of hard drive space + DeviceOffline, // device is off or needs to be woken up } export async function installApk( @@ -184,39 +192,38 @@ export async function installApk( device: Device, apk: string, ): Promise { - const debug = Debug(`${modulePrefix}:${installApk.name}`); + const debug = Debug(`${modulePrefix}:${installApk.name}`) const platformTools = await getSDKPackage( path.join(sdk.root, 'platform-tools'), - ); - const adbBin = path.join(platformTools.location, 'adb'); - const args = ['-s', device.serial, 'install', '-r', '-t', apk]; - debug('Invoking adb with args: %O', args); + ) + const adbBin = path.join(platformTools.location, 'adb') + const args = ['-s', device.serial, 'install', '-r', '-t', apk] + debug('Invoking adb with args: %O', args) const p = spawn(adbBin, args, { stdio: 'pipe', env: supplementProcessEnv(sdk), - }); + }) return new Promise((resolve, reject) => { - p.on('close', code => { - if (code === 0) { - resolve(); - } else { - reject(new ADBException(`Non-zero exit code from adb: ${code}`)); - } - }); - - p.on('error', err => { - debug('adb install error: %O', err); - reject(err); - }); + p.on('close', (code) => { + if (code === 0) + resolve() + else + reject(new ADBException(`Non-zero exit code from adb: ${code}`)) + }) + + p.on('error', (err) => { + debug('adb install error: %O', err) + reject(err) + }) p.stderr.pipe(split2()).pipe( through2((chunk, enc, cb) => { - const line = chunk.toString(); + const line = chunk.toString() - debug('adb install: %O', line); - const event = parseAdbInstallOutput(line); + debug('adb install: %O', line) + const event = parseAdbInstallOutput(line) if (event === ADBEvent.IncompatibleUpdateFailure) { reject( @@ -224,48 +231,53 @@ export async function installApk( `Encountered adb error: ${ADBEvent[event]}.`, ERR_INCOMPATIBLE_UPDATE, ), - ); - } else if (event === ADBEvent.NewerVersionOnDeviceFailure) { + ) + } + else if (event === ADBEvent.NewerVersionOnDeviceFailure) { reject( new ADBException( `Encountered adb error: ${ADBEvent[event]}.`, ERR_VERSION_DOWNGRADE, ), - ); - } else if (event === ADBEvent.NewerSdkRequiredOnDeviceFailure) { + ) + } + else if (event === ADBEvent.NewerSdkRequiredOnDeviceFailure) { reject( new ADBException( `Encountered adb error: ${ADBEvent[event]}.`, ERR_MIN_SDK_VERSION, ), - ); - } else if (event === ADBEvent.NoCertificates) { + ) + } + else if (event === ADBEvent.NoCertificates) { reject( new ADBException( `Encountered adb error: ${ADBEvent[event]}.`, ERR_NO_CERTIFICATES, ), - ); - } else if (event === ADBEvent.NotEnoughSpace) { + ) + } + else if (event === ADBEvent.NotEnoughSpace) { reject( new ADBException( `Encountered adb error: ${ADBEvent[event]}.`, ERR_NOT_ENOUGH_SPACE, ), - ); - } else if (event === ADBEvent.DeviceOffline) { + ) + } + else if (event === ADBEvent.DeviceOffline) { reject( new ADBException( `Encountered adb error: ${ADBEvent[event]}.`, ERR_DEVICE_OFFLINE, ), - ); + ) } - cb(); + cb() }), - ); - }); + ) + }) } export async function closeApp( @@ -273,11 +285,11 @@ export async function closeApp( device: Device, app: string, ): Promise { - const debug = Debug(`${modulePrefix}:${closeApp.name}`); - const args = ['-s', device.serial, 'shell', 'am', 'force-stop', app]; + const debug = Debug(`${modulePrefix}:${closeApp.name}`) + const args = ['-s', device.serial, 'shell', 'am', 'force-stop', app] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args) } export async function uninstallApp( @@ -285,48 +297,37 @@ export async function uninstallApp( device: Device, app: string, ): Promise { - const debug = Debug(`${modulePrefix}:${uninstallApp.name}`); - const args = ['-s', device.serial, 'uninstall', app]; + const debug = Debug(`${modulePrefix}:${uninstallApp.name}`) + const args = ['-s', device.serial, 'uninstall', app] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args); -} - -export enum ADBEvent { - IncompatibleUpdateFailure, // signatures do not match the previously installed version - NewerVersionOnDeviceFailure, // version of app on device is newer than the one being deployed - NewerSdkRequiredOnDeviceFailure, // device does not meet minSdkVersion requirement - NoCertificates, // no certificates in APK, likely due to improper signing config - NotEnoughSpace, // device is out of hard drive space - DeviceOffline, // device is off or needs to be woken up + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args) } export function parseAdbInstallOutput(line: string): ADBEvent | undefined { - const debug = Debug(`${modulePrefix}:${parseAdbInstallOutput.name}`); - let event: ADBEvent | undefined; - - if (line.includes('INSTALL_FAILED_UPDATE_INCOMPATIBLE')) { - event = ADBEvent.IncompatibleUpdateFailure; - } else if (line.includes('INSTALL_FAILED_VERSION_DOWNGRADE')) { - event = ADBEvent.NewerVersionOnDeviceFailure; - } else if (line.includes('INSTALL_FAILED_OLDER_SDK')) { - event = ADBEvent.NewerSdkRequiredOnDeviceFailure; - } else if (line.includes('INSTALL_PARSE_FAILED_NO_CERTIFICATES')) { - event = ADBEvent.NoCertificates; - } else if ( - line.includes('INSTALL_FAILED_INSUFFICIENT_STORAGE') || - line.includes('not enough space') - ) { - event = ADBEvent.NotEnoughSpace; - } else if (line.includes('device offline')) { - event = ADBEvent.DeviceOffline; - } - - if (typeof event !== 'undefined') { - debug('Parsed event from adb install output: %s', ADBEvent[event]); - } - - return event; + const debug = Debug(`${modulePrefix}:${parseAdbInstallOutput.name}`) + let event: ADBEvent | undefined + + if (line.includes('INSTALL_FAILED_UPDATE_INCOMPATIBLE')) + event = ADBEvent.IncompatibleUpdateFailure + else if (line.includes('INSTALL_FAILED_VERSION_DOWNGRADE')) + event = ADBEvent.NewerVersionOnDeviceFailure + else if (line.includes('INSTALL_FAILED_OLDER_SDK')) + event = ADBEvent.NewerSdkRequiredOnDeviceFailure + else if (line.includes('INSTALL_PARSE_FAILED_NO_CERTIFICATES')) + event = ADBEvent.NoCertificates + else if ( + line.includes('INSTALL_FAILED_INSUFFICIENT_STORAGE') + || line.includes('not enough space') + ) + event = ADBEvent.NotEnoughSpace + else if (line.includes('device offline')) + event = ADBEvent.DeviceOffline + + if (typeof event !== 'undefined') + debug('Parsed event from adb install output: %s', ADBEvent[event]) + + return event } export async function startActivity( @@ -335,7 +336,7 @@ export async function startActivity( packageName: string, activityName: string, ): Promise { - const debug = Debug(`${modulePrefix}:${startActivity.name}`); + const debug = Debug(`${modulePrefix}:${startActivity.name}`) const args = [ '-s', device.serial, @@ -345,28 +346,28 @@ export async function startActivity( '-W', '-n', `${packageName}/${activityName}`, - ]; + ] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args, { timeout: 5000 }) } export function parseAdbDevices(output: string): Device[] { - const debug = Debug(`${modulePrefix}:${parseAdbDevices.name}`); - const re = /^([\S]+)\s+([a-z\s]+)\s+(.*)$/; - const ipRe = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/; - const lines = output.split(os.EOL); + const debug = Debug(`${modulePrefix}:${parseAdbDevices.name}`) + const re = /^([\S]+)\s+([a-z\s]+)\s+(.*)$/ + const ipRe = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ + const lines = output.split(os.EOL) - debug('Parsing adb devices from output lines: %O', lines); + debug('Parsing adb devices from output lines: %O', lines) - const devices: Device[] = []; + const devices: Device[] = [] for (const line of lines) { if (line && !line.startsWith('List')) { - const m = line.match(re); + const m = line.match(re) if (m) { - const [, serial, state, description] = m; + const [, serial, state, description] = m const properties = description .split(/\s+/) .map(prop => (prop.includes(':') ? prop.split(':') : undefined)) @@ -375,25 +376,24 @@ export function parseAdbDevices(output: string): Device[] { typeof kv !== 'undefined' && kv.length >= 2, ) .reduce((acc, [k, v]) => { - if (k && v) { - acc[k.trim()] = v.trim(); - } + if (k && v) + acc[k.trim()] = v.trim() - return acc; - }, {} as { [key: string]: string | undefined }); + return acc + }, {} as { [key: string]: string | undefined }) - const isIP = !!serial.match(ipRe); - const isGenericDevice = (properties['device'] || '').startsWith( + const isIP = !!serial.match(ipRe) + const isGenericDevice = (properties.device || '').startsWith( 'generic', - ); - const type = - 'usb' in properties || - isIP || - !serial.startsWith('emulator') || - !isGenericDevice + ) + const type + = ('usb' in properties + || isIP + || !serial.startsWith('emulator') + || !isGenericDevice) ? 'hardware' - : 'emulator'; - const connection = 'usb' in properties ? 'usb' : isIP ? 'tcpip' : null; + : 'emulator' + const connection = 'usb' in properties ? 'usb' : isIP ? 'tcpip' : null devices.push({ serial, @@ -403,20 +403,21 @@ export function parseAdbDevices(output: string): Device[] { properties, // We might not know these yet manufacturer: '', - model: properties['model'] || '', - product: properties['product'] || '', + model: properties.model || '', + product: properties.product || '', sdkVersion: '', - }); - } else { + }) + } + else { debug( 'adb devices output line does not match expected regex: %O', line, - ); + ) } } } - return devices; + return devices } export async function forwardPorts( @@ -424,17 +425,17 @@ export async function forwardPorts( device: Device, ports: Ports, ): Promise { - const debug = Debug(`${modulePrefix}:${forwardPorts.name}`); + const debug = Debug(`${modulePrefix}:${forwardPorts.name}`) const args = [ '-s', device.serial, 'reverse', `tcp:${ports.device}`, `tcp:${ports.host}`, - ]; + ] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args, { timeout: 5000 }) } export async function unforwardPorts( @@ -442,21 +443,21 @@ export async function unforwardPorts( device: Device, ports: Ports, ): Promise { - const debug = Debug(`${modulePrefix}:${unforwardPorts.name}`); + const debug = Debug(`${modulePrefix}:${unforwardPorts.name}`) const args = [ '-s', device.serial, 'reverse', '--remove', `tcp:${ports.device}`, - ]; + ] - debug('Invoking adb with args: %O', args); - await execAdb(sdk, args, { timeout: 5000 }); + debug('Invoking adb with args: %O', args) + await execAdb(sdk, args, { timeout: 5000 }) } export interface ExecADBOptions { - timeout?: number; + timeout?: number } export async function execAdb( @@ -464,55 +465,52 @@ export async function execAdb( args: string[], options: ExecADBOptions = {}, ): Promise { - const debug = Debug(`${modulePrefix}:${execAdb.name}`); - let timer: NodeJS.Timer | undefined; - - const retry = async () => { - const msg = `ADBs is unresponsive after ${options.timeout}ms, killing server and retrying...\n`; - if (process.argv.includes('--json')) { - debug(msg); - } else { - process.stderr.write(msg); - } - - debug( - 'ADB timeout of %O reached, killing server and retrying...', - options.timeout, - ); - debug('Invoking adb with args: %O', ['kill-server']); - await execAdb(sdk, ['kill-server']); - debug('Invoking adb with args: %O', ['start-server']); - await execAdb(sdk, ['start-server']); - debug('Retrying...'); - return run(); - }; + const debug = Debug(`${modulePrefix}:${execAdb.name}`) + let timer: NodeJS.Timer | undefined const run = async () => { const platformTools = await getSDKPackage( path.join(sdk.root, 'platform-tools'), - ); - const adbBin = path.join(platformTools.location, 'adb'); + ) + const adbBin = path.join(platformTools.location, 'adb') const { stdout } = await execFile(adbBin, args, { env: supplementProcessEnv(sdk), - }); + }) if (timer) { - clearTimeout(timer); - timer = undefined; + clearTimeout(timer) + timer = undefined } - return stdout; - }; + return stdout + } - return new Promise((resolve, reject) => { - if (options.timeout) { - timer = setTimeout(() => retry().then(resolve, reject), options.timeout); - } + const retry = async () => { + const msg = `ADBs is unresponsive after ${options.timeout}ms, killing server and retrying...\n` + if (process.argv.includes('--json')) + debug(msg) + else + process.stderr.write(msg) - run().then(resolve, err => { - if (!timer) { - reject(err); - } - }); - }); + debug( + 'ADB timeout of %O reached, killing server and retrying...', + options.timeout, + ) + debug('Invoking adb with args: %O', ['kill-server']) + await execAdb(sdk, ['kill-server']) + debug('Invoking adb with args: %O', ['start-server']) + await execAdb(sdk, ['start-server']) + debug('Retrying...') + return run() + } + + return new Promise((resolve, reject) => { + if (options.timeout) + timer = setTimeout(() => retry().then(resolve, reject), options.timeout) + + run().then(resolve, (err) => { + if (!timer) + reject(err) + }) + }) } diff --git a/src/android/utils/apk.ts b/src/android/utils/apk.ts index 04263cd..64753f7 100644 --- a/src/android/utils/apk.ts +++ b/src/android/utils/apk.ts @@ -1,46 +1,46 @@ -import { unzip } from '../../utils/unzip'; +import { unzip } from '../../utils/unzip' -import { BinaryXmlParser } from './binary-xml-parser'; +import { BinaryXmlParser } from './binary-xml-parser' export async function readAndroidManifest(apkPath: string): Promise { - let error: Error | undefined; - const chunks: Buffer[] = []; + let error: Error | undefined + const chunks: Buffer[] = [] await unzip(apkPath, async (entry, zipfile, openReadStream) => { if (entry.fileName === 'AndroidManifest.xml') { - const readStream = await openReadStream(entry); - readStream.on('error', (err: Error) => (error = err)); - readStream.on('data', (chunk: Buffer) => chunks.push(chunk)); - readStream.on('end', () => zipfile.close()); - } else { - zipfile.readEntry(); + const readStream = await openReadStream(entry) + readStream.on('error', (err: Error) => (error = err)) + readStream.on('data', (chunk: Buffer) => chunks.push(chunk)) + readStream.on('end', () => zipfile.close()) } - }); + else { + zipfile.readEntry() + } + }) - if (error) { - throw error; - } + if (error) + throw error - const buf = Buffer.concat(chunks); - const manifestBuffer = Buffer.from(buf); + const buf = Buffer.concat(chunks) + const manifestBuffer = Buffer.from(buf) - return new BinaryXmlParser(manifestBuffer).parse(); + return new BinaryXmlParser(manifestBuffer).parse() } export async function getApkInfo( apkPath: string, ): Promise<{ appId: any; activityName: any }> { - const doc = await readAndroidManifest(apkPath); - const appId = doc.attributes.find((a: any) => a.name === 'package').value; + const doc = await readAndroidManifest(apkPath) + const appId = doc.attributes.find((a: any) => a.name === 'package').value const application = doc.childNodes.find( (n: any) => n.nodeName === 'application', - ); + ) const activity = application.childNodes.find( (n: any) => n.nodeName === 'activity', - ); + ) const activityName = activity.attributes.find( (a: any) => a.name === 'name', - ).value; + ).value - return { appId, activityName }; + return { appId, activityName } } diff --git a/src/android/utils/avd.ts b/src/android/utils/avd.ts index 9c9a05d..9a8cbd1 100644 --- a/src/android/utils/avd.ts +++ b/src/android/utils/avd.ts @@ -1,9 +1,9 @@ -import { copy, mkdirp, readdir, statSafe } from '@ionic/utils-fs'; -import * as Debug from 'debug'; -import * as os from 'os'; -import * as pathlib from 'path'; +import * as os from 'node:os' +import * as pathlib from 'node:path' +import { copy, mkdirp, readdir, statSafe } from '@ionic/utils-fs' +import Debug from 'debug' -import { ASSETS_PATH } from '../../constants'; +import { ASSETS_PATH } from '../../constants' import { AVDException, ERR_INVALID_SKIN, @@ -12,111 +12,111 @@ import { ERR_SDK_UNSATISFIED_PACKAGES, ERR_UNSUITABLE_API_INSTALLATION, ERR_UNSUPPORTED_API_LEVEL, -} from '../../errors'; -import { readINI, writeINI } from '../../utils/ini'; -import { sort } from '../../utils/object'; +} from '../../errors' +import { readINI, writeINI } from '../../utils/ini' +import { sort } from '../../utils/object' -import type { SDK, SDKPackage } from './sdk'; -import { findAllSDKPackages } from './sdk'; -import type { APILevel, PartialAVDSchematic } from './sdk/api'; +import type { SDK, SDKPackage } from './sdk' +import { findAllSDKPackages } from './sdk' +import type { APILevel, PartialAVDSchematic } from './sdk/api' import { API_LEVEL_SCHEMAS, findPackageBySchemaPath, getAPILevels, -} from './sdk/api'; +} from './sdk/api' -const modulePrefix = 'native-run:android:utils:avd'; +const modulePrefix = 'native-run:android:utils:avd' export interface AVD { - readonly id: string; - readonly path: string; - readonly name: string; - readonly sdkVersion: string; - readonly screenDPI: number | null; - readonly screenWidth: number | null; - readonly screenHeight: number | null; + readonly id: string + readonly path: string + readonly name: string + readonly sdkVersion: string + readonly screenDPI: number | null + readonly screenWidth: number | null + readonly screenHeight: number | null } export interface AVDSchematic { - readonly id: string; - readonly ini: Required; - readonly configini: Required; + readonly id: string + readonly ini: Required + readonly configini: Required } export interface AVDINI { - readonly 'avd.ini.encoding': string; - readonly 'path': string; - readonly 'path.rel': string; - readonly 'target': string; + readonly 'avd.ini.encoding': string + readonly 'path': string + readonly 'path.rel': string + readonly 'target': string } export interface AVDConfigINI { - readonly 'AvdId'?: string; - readonly 'abi.type'?: string; - readonly 'avd.ini.displayname'?: string; - readonly 'avd.ini.encoding'?: string; - readonly 'hw.accelerometer'?: string; - readonly 'hw.audioInput'?: string; - readonly 'hw.battery'?: string; - readonly 'hw.camera.back'?: string; - readonly 'hw.camera.front'?: string; - readonly 'hw.cpu.arch'?: string; - readonly 'hw.cpu.ncore'?: string; - readonly 'hw.device.hash2'?: string; - readonly 'hw.device.manufacturer'?: string; - readonly 'hw.device.name'?: string; - readonly 'hw.gps'?: string; - readonly 'hw.gpu.enabled'?: string; - readonly 'hw.gpu.mode'?: string; - readonly 'hw.initialOrientation'?: string; - readonly 'hw.keyboard'?: string; - readonly 'hw.lcd.density'?: string; - readonly 'hw.lcd.height'?: string; - readonly 'hw.lcd.width'?: string; - readonly 'hw.ramSize'?: string; - readonly 'hw.sdCard'?: string; - readonly 'hw.sensors.orientation'?: string; - readonly 'hw.sensors.proximity'?: string; - readonly 'image.sysdir.1'?: string; - readonly 'sdcard.size'?: string; - readonly 'showDeviceFrame'?: string; - readonly 'skin.dynamic'?: string; - readonly 'skin.name'?: string; - readonly 'skin.path'?: string; - readonly 'tag.display'?: string; - readonly 'tag.id'?: string; + readonly 'AvdId'?: string + readonly 'abi.type'?: string + readonly 'avd.ini.displayname'?: string + readonly 'avd.ini.encoding'?: string + readonly 'hw.accelerometer'?: string + readonly 'hw.audioInput'?: string + readonly 'hw.battery'?: string + readonly 'hw.camera.back'?: string + readonly 'hw.camera.front'?: string + readonly 'hw.cpu.arch'?: string + readonly 'hw.cpu.ncore'?: string + readonly 'hw.device.hash2'?: string + readonly 'hw.device.manufacturer'?: string + readonly 'hw.device.name'?: string + readonly 'hw.gps'?: string + readonly 'hw.gpu.enabled'?: string + readonly 'hw.gpu.mode'?: string + readonly 'hw.initialOrientation'?: string + readonly 'hw.keyboard'?: string + readonly 'hw.lcd.density'?: string + readonly 'hw.lcd.height'?: string + readonly 'hw.lcd.width'?: string + readonly 'hw.ramSize'?: string + readonly 'hw.sdCard'?: string + readonly 'hw.sensors.orientation'?: string + readonly 'hw.sensors.proximity'?: string + readonly 'image.sysdir.1'?: string + readonly 'sdcard.size'?: string + readonly 'showDeviceFrame'?: string + readonly 'skin.dynamic'?: string + readonly 'skin.name'?: string + readonly 'skin.path'?: string + readonly 'tag.display'?: string + readonly 'tag.id'?: string } export const isAVDINI = (o: any): o is AVDINI => - o && - typeof o['avd.ini.encoding'] === 'string' && - typeof o['path'] === 'string' && - typeof o['path.rel'] === 'string' && - typeof o['target'] === 'string'; + o + && typeof o['avd.ini.encoding'] === 'string' + && typeof o.path === 'string' + && typeof o['path.rel'] === 'string' + && typeof o.target === 'string' export const isAVDConfigINI = (o: any): o is AVDConfigINI => - o && - (typeof o['avd.ini.displayname'] === 'undefined' || - typeof o['avd.ini.displayname'] === 'string') && - (typeof o['hw.lcd.density'] === 'undefined' || - typeof o['hw.lcd.density'] === 'string') && - (typeof o['hw.lcd.height'] === 'undefined' || - typeof o['hw.lcd.height'] === 'string') && - (typeof o['hw.lcd.width'] === 'undefined' || - typeof o['hw.lcd.width'] === 'string') && - (typeof o['image.sysdir.1'] === 'undefined' || - typeof o['image.sysdir.1'] === 'string'); + o + && (typeof o['avd.ini.displayname'] === 'undefined' + || typeof o['avd.ini.displayname'] === 'string') + && (typeof o['hw.lcd.density'] === 'undefined' + || typeof o['hw.lcd.density'] === 'string') + && (typeof o['hw.lcd.height'] === 'undefined' + || typeof o['hw.lcd.height'] === 'string') + && (typeof o['hw.lcd.width'] === 'undefined' + || typeof o['hw.lcd.width'] === 'string') + && (typeof o['image.sysdir.1'] === 'undefined' + || typeof o['image.sysdir.1'] === 'string') export async function getAVDINIs(sdk: SDK): Promise<[string, AVDINI][]> { - const debug = Debug(`${modulePrefix}:${getAVDINIs.name}`); + const debug = Debug(`${modulePrefix}:${getAVDINIs.name}`) - const contents = await readdir(sdk.avdHome); + const contents = await readdir(sdk.avdHome) const iniFilePaths = contents .filter(f => pathlib.extname(f) === '.ini') - .map(f => pathlib.resolve(sdk.avdHome, f)); + .map(f => pathlib.resolve(sdk.avdHome, f)) - debug('Discovered AVD ini files: %O', iniFilePaths); + debug('Discovered AVD ini files: %O', iniFilePaths) const iniFiles = await Promise.all( iniFilePaths.map( @@ -125,13 +125,13 @@ export async function getAVDINIs(sdk: SDK): Promise<[string, AVDINI][]> { await readINI(f, isAVDINI), ], ), - ); + ) const avdInis = iniFiles.filter( (c): c is [string, AVDINI] => typeof c[1] !== 'undefined', - ); + ) - return avdInis; + return avdInis } export function getAVDFromConfigINI( @@ -139,23 +139,23 @@ export function getAVDFromConfigINI( ini: AVDINI, configini: AVDConfigINI, ): AVD { - const inibasename = pathlib.basename(inipath); + const inibasename = pathlib.basename(inipath) const id = inibasename.substring( 0, inibasename.length - pathlib.extname(inibasename).length, - ); + ) const name = configini['avd.ini.displayname'] ? String(configini['avd.ini.displayname']) - : id.replace(/_/g, ' '); + : id.replace(/_/g, ' ') const screenDPI = configini['hw.lcd.density'] ? Number(configini['hw.lcd.density']) - : null; + : null const screenWidth = configini['hw.lcd.width'] ? Number(configini['hw.lcd.width']) - : null; + : null const screenHeight = configini['hw.lcd.height'] ? Number(configini['hw.lcd.height']) - : null; + : null return { id, @@ -165,11 +165,11 @@ export function getAVDFromConfigINI( screenDPI, screenWidth, screenHeight, - }; + } } export function getSDKVersionFromTarget(target: string): string { - return target.replace(/^android-(\d+)/, '$1'); + return target.replace(/^android-(\d+)/, '$1') } export async function getAVDFromINI( @@ -179,59 +179,58 @@ export async function getAVDFromINI( const configini = await readINI( pathlib.resolve(ini.path, 'config.ini'), isAVDConfigINI, - ); + ) - if (configini) { - return getAVDFromConfigINI(inipath, ini, configini); - } + if (configini) + return getAVDFromConfigINI(inipath, ini, configini) } export async function getInstalledAVDs(sdk: SDK): Promise { - const avdInis = await getAVDINIs(sdk); + const avdInis = await getAVDINIs(sdk) const possibleAvds = await Promise.all( avdInis.map(([inipath, ini]) => getAVDFromINI(inipath, ini)), - ); + ) const avds = possibleAvds.filter( (avd): avd is AVD => typeof avd !== 'undefined', - ); + ) - return avds; + return avds } export async function getDefaultAVDSchematic(sdk: SDK): Promise { - const debug = Debug(`${modulePrefix}:${getDefaultAVDSchematic.name}`); - const packages = await findAllSDKPackages(sdk); - const apis = await getAPILevels(packages); - const errors: AVDException[] = []; + const debug = Debug(`${modulePrefix}:${getDefaultAVDSchematic.name}`) + const packages = await findAllSDKPackages(sdk) + const apis = await getAPILevels(packages) + const errors: AVDException[] = [] for (const api of apis) { try { - const schematic = await getAVDSchematicFromAPILevel(sdk, packages, api); - debug('Using schematic %s for default AVD', schematic.id); - - return schematic; - } catch (e) { - if (!(e instanceof AVDException)) { - throw e; - } - errors.push(e); - debug('Issue with API %s: %s', api.apiLevel, e.message); + const schematic = await getAVDSchematicFromAPILevel(sdk, packages, api) + debug('Using schematic %s for default AVD', schematic.id) + + return schematic + } + catch (e) { + if (!(e instanceof AVDException)) + throw e + + errors.push(e) + debug('Issue with API %s: %s', api.apiLevel, e.message) } } if (errors.length > 0) { const unsupportedError = errors.find( e => e.code === ERR_UNSUPPORTED_API_LEVEL, - ); - if (unsupportedError) { - throw unsupportedError; - } + ) + if (unsupportedError) + throw unsupportedError } throw new AVDException( 'No suitable API installation found. Use --sdk-info to reveal missing packages and other issues.', ERR_UNSUITABLE_API_INSTALLATION, 1, - ); + ) } export async function getAVDSchematicFromAPILevel( @@ -239,16 +238,16 @@ export async function getAVDSchematicFromAPILevel( packages: readonly SDKPackage[], api: APILevel, ): Promise { - const schema = API_LEVEL_SCHEMAS.find(s => s.apiLevel === api.apiLevel); + const schema = API_LEVEL_SCHEMAS.find(s => s.apiLevel === api.apiLevel) if (!schema) { throw new AVDException( `Unsupported API level: ${api.apiLevel}`, ERR_UNSUPPORTED_API_LEVEL, - ); + ) } - const missingPackages = schema.validate(packages); + const missingPackages = schema.validate(packages) if (missingPackages.length > 0) { throw new AVDException( @@ -257,44 +256,43 @@ export async function getAVDSchematicFromAPILevel( .join(', ')}`, ERR_SDK_UNSATISFIED_PACKAGES, 1, - ); + ) } - return createAVDSchematic(sdk, await schema.loadPartialAVDSchematic()); + return createAVDSchematic(sdk, await schema.loadPartialAVDSchematic()) } export async function getDefaultAVD( sdk: SDK, avds: readonly AVD[], ): Promise { - const defaultAvdSchematic = await getDefaultAVDSchematic(sdk); - const defaultAvd = avds.find(avd => avd.id === defaultAvdSchematic.id); + const defaultAvdSchematic = await getDefaultAVDSchematic(sdk) + const defaultAvd = avds.find(avd => avd.id === defaultAvdSchematic.id) - if (defaultAvd) { - return defaultAvd; - } + if (defaultAvd) + return defaultAvd - return createAVD(sdk, defaultAvdSchematic); + return createAVD(sdk, defaultAvdSchematic) } export async function createAVD( sdk: SDK, schematic: AVDSchematic, ): Promise { - const { id, ini, configini } = schematic; + const { id, ini, configini } = schematic - await mkdirp(pathlib.join(sdk.avdHome, `${id}.avd`)); + await mkdirp(pathlib.join(sdk.avdHome, `${id}.avd`)) await Promise.all([ writeINI(pathlib.join(sdk.avdHome, `${id}.ini`), ini), writeINI(pathlib.join(sdk.avdHome, `${id}.avd`, 'config.ini'), configini), - ]); + ]) return getAVDFromConfigINI( pathlib.join(sdk.avdHome, `${id}.ini`), ini, configini, - ); + ) } export async function createAVDSchematic( @@ -304,24 +302,24 @@ export async function createAVDSchematic( const sysimage = findPackageBySchemaPath( sdk.packages || [], new RegExp(`^system-images;${partialSchematic.ini.target}`), - ); + ) if (!sysimage) { throw new AVDException( `Cannot create AVD schematic for ${partialSchematic.id}: missing system image.`, ERR_MISSING_SYSTEM_IMAGE, - ); + ) } - const avdpath = pathlib.join(sdk.avdHome, `${partialSchematic.id}.avd`); + const avdpath = pathlib.join(sdk.avdHome, `${partialSchematic.id}.avd`) const skinpath = getSkinPathByName( sdk, partialSchematic.configini['skin.name'], - ); - const sysdir = pathlib.relative(sdk.root, sysimage.location); - const [, , tagid] = sysimage.path.split(';'); - const arch = - os.arch() === 'arm64' ? 'arm64' : partialSchematic.configini['abi.type']; + ) + const sysdir = pathlib.relative(sdk.root, sysimage.location) + const [, , tagid] = sysimage.path.split(';') + const arch + = os.arch() === 'arm64' ? 'arm64' : partialSchematic.configini['abi.type'] const schematic: AVDSchematic = { id: partialSchematic.id, ini: sort({ @@ -337,38 +335,38 @@ export async function createAVDSchematic( 'image.sysdir.1': sysdir, 'tag.id': tagid, }), - }; + } - await validateAVDSchematic(sdk, schematic); + await validateAVDSchematic(sdk, schematic) - return schematic; + return schematic } export async function validateAVDSchematic( sdk: SDK, schematic: AVDSchematic, ): Promise { - const { configini } = schematic; - const skin = configini['skin.name']; - const skinpath = configini['skin.path']; - const sysdir = configini['image.sysdir.1']; + const { configini } = schematic + const skin = configini['skin.name'] + const skinpath = configini['skin.path'] + const sysdir = configini['image.sysdir.1'] if (!skinpath) { throw new AVDException( `${schematic.id} does not have a skin defined.`, ERR_INVALID_SKIN, - ); + ) } if (!sysdir) { throw new AVDException( `${schematic.id} does not have a system image defined.`, ERR_INVALID_SYSTEM_IMAGE, - ); + ) } - await validateSkin(sdk, skin, skinpath); - await validateSystemImagePath(sdk, sysdir); + await validateSkin(sdk, skin, skinpath) + await validateSystemImagePath(sdk, sysdir) } export async function validateSkin( @@ -376,18 +374,17 @@ export async function validateSkin( skin: string, skinpath: string, ): Promise { - const debug = Debug(`${modulePrefix}:${validateSkin.name}`); - const p = pathlib.join(skinpath, 'layout'); + const debug = Debug(`${modulePrefix}:${validateSkin.name}`) + const p = pathlib.join(skinpath, 'layout') - debug('Checking skin layout file: %s', p); + debug('Checking skin layout file: %s', p) - const stat = await statSafe(p); + const stat = await statSafe(p) - if (stat?.isFile()) { - return; - } + if (stat?.isFile()) + return - await copySkin(sdk, skin, skinpath); + await copySkin(sdk, skin, skinpath) } export async function copySkin( @@ -395,45 +392,46 @@ export async function copySkin( skin: string, skinpath: string, ): Promise { - const debug = Debug(`${modulePrefix}:${copySkin.name}`); - const skinsrc = pathlib.resolve(ASSETS_PATH, 'android', 'skins', skin); + const debug = Debug(`${modulePrefix}:${copySkin.name}`) + const skinsrc = pathlib.resolve(ASSETS_PATH, 'android', 'skins', skin) - const stat = await statSafe(skinsrc); + const stat = await statSafe(skinsrc) if (stat?.isDirectory()) { - debug('Copying skin from %s to %s', skinsrc, skinpath); + debug('Copying skin from %s to %s', skinsrc, skinpath) try { - return await copy(skinsrc, skinpath); - } catch (e) { - debug('Error while copying skin: %O', e); + return await copy(skinsrc, skinpath) + } + catch (e) { + debug('Error while copying skin: %O', e) } } - throw new AVDException(`${skinpath} is an invalid skin.`, ERR_INVALID_SKIN); + throw new AVDException(`${skinpath} is an invalid skin.`, ERR_INVALID_SKIN) } export async function validateSystemImagePath( sdk: SDK, sysdir: string, ): Promise { - const debug = Debug(`${modulePrefix}:${validateSystemImagePath.name}`); - const p = pathlib.join(sdk.root, sysdir, 'package.xml'); + const debug = Debug(`${modulePrefix}:${validateSystemImagePath.name}`) + const p = pathlib.join(sdk.root, sysdir, 'package.xml') - debug('Checking package.xml file: %s', p); + debug('Checking package.xml file: %s', p) - const stat = await statSafe(p); + const stat = await statSafe(p) if (!stat || !stat.isFile()) { throw new AVDException( `${p} is an invalid system image package.`, ERR_INVALID_SYSTEM_IMAGE, - ); + ) } } export function getSkinPathByName(sdk: SDK, name: string): string { - const path = pathlib.join(sdk.root, 'skins', name); + const path = pathlib.join(sdk.root, 'skins', name) - return path; + return path } diff --git a/src/android/utils/binary-xml-parser.ts b/src/android/utils/binary-xml-parser.ts index d0a6a01..afb3602 100644 --- a/src/android/utils/binary-xml-parser.ts +++ b/src/android/utils/binary-xml-parser.ts @@ -17,17 +17,17 @@ https://github.com/openstf/adbkit-apkreader/blob/368f6b207c57e82fa7373c1608920ca7f4a8904c/lib/apkreader/parser/binaryxml.js */ -import * as assert from 'assert'; +import * as assert from 'node:assert' -// import * as Debug from 'debug'; -import { Exception } from '../../errors'; +// import Debug from 'debug'; +import { Exception } from '../../errors' // const debug = Debug('native-run:android:util:binary-xml-parser'); const NodeType = { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, CDATA_SECTION_NODE: 4, -}; +} const ChunkType = { NULL: 0x0000, @@ -40,21 +40,21 @@ const ChunkType = { XML_START_ELEMENT: 0x0102, XML_END_ELEMENT: 0x0103, XML_CDATA: 0x0104, - XML_LAST_CHUNK: 0x017f, + XML_LAST_CHUNK: 0x017F, XML_RESOURCE_MAP: 0x0180, TABLE_PACKAGE: 0x0200, TABLE_TYPE: 0x0201, TABLE_TYPE_SPEC: 0x0202, -}; +} const StringFlags = { SORTED: 1 << 0, UTF8: 1 << 8, -}; +} // Taken from android.util.TypedValue const TypedValue = { - COMPLEX_MANTISSA_MASK: 0x00ffffff, + COMPLEX_MANTISSA_MASK: 0x00FFFFFF, COMPLEX_MANTISSA_SHIFT: 0x00000008, COMPLEX_RADIX_0p23: 0x00000003, COMPLEX_RADIX_16p7: 0x00000001, @@ -66,102 +66,102 @@ const TypedValue = { COMPLEX_UNIT_FRACTION: 0x00000000, COMPLEX_UNIT_FRACTION_PARENT: 0x00000001, COMPLEX_UNIT_IN: 0x00000004, - COMPLEX_UNIT_MASK: 0x0000000f, + COMPLEX_UNIT_MASK: 0x0000000F, COMPLEX_UNIT_MM: 0x00000005, COMPLEX_UNIT_PT: 0x00000003, COMPLEX_UNIT_PX: 0x00000000, COMPLEX_UNIT_SHIFT: 0x00000000, COMPLEX_UNIT_SP: 0x00000002, DENSITY_DEFAULT: 0x00000000, - DENSITY_NONE: 0x0000ffff, + DENSITY_NONE: 0x0000FFFF, TYPE_ATTRIBUTE: 0x00000002, TYPE_DIMENSION: 0x00000005, - TYPE_FIRST_COLOR_INT: 0x0000001c, + TYPE_FIRST_COLOR_INT: 0x0000001C, TYPE_FIRST_INT: 0x00000010, TYPE_FLOAT: 0x00000004, TYPE_FRACTION: 0x00000006, TYPE_INT_BOOLEAN: 0x00000012, - TYPE_INT_COLOR_ARGB4: 0x0000001e, - TYPE_INT_COLOR_ARGB8: 0x0000001c, - TYPE_INT_COLOR_RGB4: 0x0000001f, - TYPE_INT_COLOR_RGB8: 0x0000001d, + TYPE_INT_COLOR_ARGB4: 0x0000001E, + TYPE_INT_COLOR_ARGB8: 0x0000001C, + TYPE_INT_COLOR_RGB4: 0x0000001F, + TYPE_INT_COLOR_RGB8: 0x0000001D, TYPE_INT_DEC: 0x00000010, TYPE_INT_HEX: 0x00000011, - TYPE_LAST_COLOR_INT: 0x0000001f, - TYPE_LAST_INT: 0x0000001f, + TYPE_LAST_COLOR_INT: 0x0000001F, + TYPE_LAST_INT: 0x0000001F, TYPE_NULL: 0x00000000, TYPE_REFERENCE: 0x00000001, TYPE_STRING: 0x00000003, -}; +} export class BinaryXmlParser { - cursor = 0; - strings: string[] = []; - resources: any[] = []; - document: any; - parent: any; - stack: any[] = []; - debug = false; + cursor = 0 + strings: string[] = [] + resources: any[] = [] + document: any + parent: any + stack: any[] = [] + debug = false constructor(public buffer: Buffer, options: any = {}) { - this.debug = options.debug || false; + this.debug = options.debug || false } readU8(): number { // debug('readU8'); // debug('cursor:', this.cursor); - const val = this.buffer[this.cursor]; + const val = this.buffer[this.cursor] // debug('value:', val); - this.cursor += 1; - return val; + this.cursor += 1 + return val } readU16(): number { // debug('readU16'); // debug('cursor:', this.cursor); - const val = this.buffer.readUInt16LE(this.cursor); + const val = this.buffer.readUInt16LE(this.cursor) // debug('value:', val); - this.cursor += 2; - return val; + this.cursor += 2 + return val } readS32(): number { // debug('readS32'); // debug('cursor:', this.cursor); - const val = this.buffer.readInt32LE(this.cursor); + const val = this.buffer.readInt32LE(this.cursor) // debug('value:', val); - this.cursor += 4; - return val; + this.cursor += 4 + return val } readU32(): number { // debug('readU32'); // debug('cursor:', this.cursor); - const val = this.buffer.readUInt32LE(this.cursor); + const val = this.buffer.readUInt32LE(this.cursor) // debug('value:', val); - this.cursor += 4; - return val; + this.cursor += 4 + return val } readLength8(): number { // debug('readLength8'); - let len = this.readU8(); + let len = this.readU8() if (len & 0x80) { - len = (len & 0x7f) << 8; - len += this.readU8(); + len = (len & 0x7F) << 8 + len += this.readU8() } // debug('length:', len); - return len; + return len } readLength16(): number { // debug('readLength16'); - let len = this.readU16(); + let len = this.readU16() if (len & 0x8000) { - len = (len & 0x7fff) << 16; - len += this.readU16(); + len = (len & 0x7FFF) << 16 + len += this.readU16() } // debug('length:', len); - return len; + return len } readDimension(): any { @@ -171,36 +171,36 @@ export class BinaryXmlParser { value: null, unit: null, rawUnit: null, - }; + } - const value = this.readU32(); - const unit = dimension.value & 0xff; + const value = this.readU32() + const unit = dimension.value & 0xFF - dimension.value = value >> 8; - dimension.rawUnit = unit; + dimension.value = value >> 8 + dimension.rawUnit = unit switch (unit) { case TypedValue.COMPLEX_UNIT_MM: - dimension.unit = 'mm'; - break; + dimension.unit = 'mm' + break case TypedValue.COMPLEX_UNIT_PX: - dimension.unit = 'px'; - break; + dimension.unit = 'px' + break case TypedValue.COMPLEX_UNIT_DIP: - dimension.unit = 'dp'; - break; + dimension.unit = 'dp' + break case TypedValue.COMPLEX_UNIT_SP: - dimension.unit = 'sp'; - break; + dimension.unit = 'sp' + break case TypedValue.COMPLEX_UNIT_PT: - dimension.unit = 'pt'; - break; + dimension.unit = 'pt' + break case TypedValue.COMPLEX_UNIT_IN: - dimension.unit = 'in'; - break; + dimension.unit = 'in' + break } - return dimension; + return dimension } readFraction(): any { @@ -210,36 +210,36 @@ export class BinaryXmlParser { value: null, type: null, rawType: null, - }; + } - const value = this.readU32(); - const type = value & 0xf; + const value = this.readU32() + const type = value & 0xF - fraction.value = this.convertIntToFloat(value >> 4); - fraction.rawType = type; + fraction.value = this.convertIntToFloat(value >> 4) + fraction.rawType = type switch (type) { case TypedValue.COMPLEX_UNIT_FRACTION: - fraction.type = '%'; - break; + fraction.type = '%' + break case TypedValue.COMPLEX_UNIT_FRACTION_PARENT: - fraction.type = '%p'; - break; + fraction.type = '%p' + break } - return fraction; + return fraction } readHex24(): string { // debug('readHex24'); - const val = (this.readU32() & 0xffffff).toString(16); - return val; + const val = (this.readU32() & 0xFFFFFF).toString(16) + return val } readHex32(): string { // debug('readHex32'); - const val = this.readU32().toString(16); - return val; + const val = this.readU32().toString(16) + return val } readTypedValue(): any { @@ -249,146 +249,145 @@ export class BinaryXmlParser { value: null, type: null, rawType: null, - }; + } - const start = this.cursor; + const start = this.cursor - let size = this.readU16(); - /* const zero = */ this.readU8(); - const dataType = this.readU8(); + let size = this.readU16() + /* const zero = */ this.readU8() + const dataType = this.readU8() // Yes, there has been a real world APK where the size is malformed. - if (size === 0) { - size = 8; - } + if (size === 0) + size = 8 - typedValue.rawType = dataType; + typedValue.rawType = dataType switch (dataType) { case TypedValue.TYPE_INT_DEC: - typedValue.value = this.readS32(); - typedValue.type = 'int_dec'; - break; + typedValue.value = this.readS32() + typedValue.type = 'int_dec' + break case TypedValue.TYPE_INT_HEX: - typedValue.value = this.readS32(); - typedValue.type = 'int_hex'; - break; + typedValue.value = this.readS32() + typedValue.type = 'int_hex' + break case TypedValue.TYPE_STRING: { - const ref = this.readS32(); - typedValue.value = ref > 0 ? this.strings[ref] : ''; - typedValue.type = 'string'; - break; + const ref = this.readS32() + typedValue.value = ref > 0 ? this.strings[ref] : '' + typedValue.type = 'string' + break } case TypedValue.TYPE_REFERENCE: { - const id = this.readU32(); - typedValue.value = `resourceId:0x${id.toString(16)}`; - typedValue.type = 'reference'; - break; + const id = this.readU32() + typedValue.value = `resourceId:0x${id.toString(16)}` + typedValue.type = 'reference' + break } case TypedValue.TYPE_INT_BOOLEAN: - typedValue.value = this.readS32() !== 0; - typedValue.type = 'boolean'; - break; + typedValue.value = this.readS32() !== 0 + typedValue.type = 'boolean' + break case TypedValue.TYPE_NULL: - this.readU32(); - typedValue.value = null; - typedValue.type = 'null'; - break; + this.readU32() + typedValue.value = null + typedValue.type = 'null' + break case TypedValue.TYPE_INT_COLOR_RGB8: - typedValue.value = this.readHex24(); - typedValue.type = 'rgb8'; - break; + typedValue.value = this.readHex24() + typedValue.type = 'rgb8' + break case TypedValue.TYPE_INT_COLOR_RGB4: - typedValue.value = this.readHex24(); - typedValue.type = 'rgb4'; - break; + typedValue.value = this.readHex24() + typedValue.type = 'rgb4' + break case TypedValue.TYPE_INT_COLOR_ARGB8: - typedValue.value = this.readHex32(); - typedValue.type = 'argb8'; - break; + typedValue.value = this.readHex32() + typedValue.type = 'argb8' + break case TypedValue.TYPE_INT_COLOR_ARGB4: - typedValue.value = this.readHex32(); - typedValue.type = 'argb4'; - break; + typedValue.value = this.readHex32() + typedValue.type = 'argb4' + break case TypedValue.TYPE_DIMENSION: - typedValue.value = this.readDimension(); - typedValue.type = 'dimension'; - break; + typedValue.value = this.readDimension() + typedValue.type = 'dimension' + break case TypedValue.TYPE_FRACTION: - typedValue.value = this.readFraction(); - typedValue.type = 'fraction'; - break; + typedValue.value = this.readFraction() + typedValue.type = 'fraction' + break default: { // const type = dataType.toString(16); // debug(`Not sure what to do with typed value of type 0x${type}, falling back to reading an uint32.`); - typedValue.value = this.readU32(); - typedValue.type = 'unknown'; + typedValue.value = this.readU32() + typedValue.type = 'unknown' } } // Ensure we consume the whole value - const end = start + size; + const end = start + size if (this.cursor !== end) { // const type = dataType.toString(16); // const diff = end - this.cursor; // debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed end \ // of typed value of type 0x${type}. The typed value started at offset ${start} \ // and is supposed to end at offset ${end}. Ignoring the rest of the value.`); - this.cursor = end; + this.cursor = end } - return typedValue; + return typedValue } // https://twitter.com/kawasima/status/427730289201139712 convertIntToFloat(int: number): number { - const buf = new ArrayBuffer(4); - new Int32Array(buf)[0] = int; - return new Float32Array(buf)[0]; + const buf = new ArrayBuffer(4) + new Int32Array(buf)[0] = int + return new Float32Array(buf)[0] } readString(encoding: string): string { // debug('readString', encoding); - let stringLength; - let byteLength; - let value; + let stringLength + let byteLength + let value switch (encoding) { case 'utf-8': - stringLength = this.readLength8(); + stringLength = this.readLength8() // debug('stringLength:', stringLength); - byteLength = this.readLength8(); + byteLength = this.readLength8() // debug('byteLength:', byteLength); value = this.buffer.toString( encoding, this.cursor, (this.cursor += byteLength), - ); + ) // debug('value:', value); - assert.equal(this.readU8(), 0, 'String must end with trailing zero'); - return value; + assert.equal(this.readU8(), 0, 'String must end with trailing zero') + return value case 'ucs2': - stringLength = this.readLength16(); + stringLength = this.readLength16() // debug('stringLength:', stringLength); - byteLength = stringLength * 2; + byteLength = stringLength * 2 // debug('byteLength:', byteLength); value = this.buffer.toString( encoding, this.cursor, (this.cursor += byteLength), - ); + ) // debug('value:', value); - assert.equal(this.readU16(), 0, 'String must end with trailing zero'); - return value; + assert.equal(this.readU16(), 0, 'String must end with trailing zero') + return value default: - throw new Exception(`Unsupported encoding '${encoding}'`); + throw new Exception(`Unsupported encoding '${encoding}'`) } } readChunkHeader(): { - startOffset: number; - chunkType: number; - headerSize: number; - chunkSize: number; + startOffset: number + chunkType: number + headerSize: number + chunkSize: number } { // debug('readChunkHeader'); const header = { @@ -396,75 +395,74 @@ export class BinaryXmlParser { chunkType: this.readU16(), headerSize: this.readU16(), chunkSize: this.readU32(), - }; + } // debug('startOffset:', header.startOffset); // debug('chunkType:', header.chunkType); // debug('headerSize:', header.headerSize); // debug('chunkSize:', header.chunkSize); - return header; + return header } readStringPool(header: any): null { // debug('readStringPool'); - header.stringCount = this.readU32(); + header.stringCount = this.readU32() // debug('stringCount:', header.stringCount); - header.styleCount = this.readU32(); + header.styleCount = this.readU32() // debug('styleCount:', header.styleCount); - header.flags = this.readU32(); + header.flags = this.readU32() // debug('flags:', header.flags); - header.stringsStart = this.readU32(); + header.stringsStart = this.readU32() // debug('stringsStart:', header.stringsStart); - header.stylesStart = this.readU32(); + header.stylesStart = this.readU32() // debug('stylesStart:', header.stylesStart); - if (header.chunkType !== ChunkType.STRING_POOL) { - throw new Exception('Invalid string pool header'); - } + if (header.chunkType !== ChunkType.STRING_POOL) + throw new Exception('Invalid string pool header') - const offsets = []; + const offsets = [] for (let i = 0, l = header.stringCount; i < l; ++i) { // debug('offset:', i); - offsets.push(this.readU32()); + offsets.push(this.readU32()) } // const sorted = (header.flags & StringFlags.SORTED) === StringFlags.SORTED; // debug('sorted:', sorted); - const encoding = - (header.flags & StringFlags.UTF8) === StringFlags.UTF8 ? 'utf-8' : 'ucs2'; + const encoding + = (header.flags & StringFlags.UTF8) === StringFlags.UTF8 ? 'utf-8' : 'ucs2' // debug('encoding:', encoding); - const stringsStart = header.startOffset + header.stringsStart; - this.cursor = stringsStart; + const stringsStart = header.startOffset + header.stringsStart + this.cursor = stringsStart for (let i = 0, l = header.stringCount; i < l; ++i) { // debug('string:', i); // debug('offset:', offsets[i]); - this.cursor = stringsStart + offsets[i]; - this.strings.push(this.readString(encoding)); + this.cursor = stringsStart + offsets[i] + this.strings.push(this.readString(encoding)) } // Skip styles - this.cursor = header.startOffset + header.chunkSize; + this.cursor = header.startOffset + header.chunkSize - return null; + return null } readResourceMap(header: any): null { // debug('readResourceMap'); - const count = Math.floor((header.chunkSize - header.headerSize) / 4); - for (let i = 0; i < count; ++i) { - this.resources.push(this.readU32()); - } - return null; + const count = Math.floor((header.chunkSize - header.headerSize) / 4) + for (let i = 0; i < count; ++i) + this.resources.push(this.readU32()) + + return null } readXmlNamespaceStart(/* header */): null { // debug('readXmlNamespaceStart'); - this.readU32(); - this.readU32(); - this.readU32(); - this.readU32(); + this.readU32() + this.readU32() + this.readU32() + this.readU32() // const line = this.readU32(); // const commentRef = this.readU32(); @@ -477,16 +475,16 @@ export class BinaryXmlParser { // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0 // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0 - return null; + return null } readXmlNamespaceEnd(/* header */): null { // debug('readXmlNamespaceEnd'); - this.readU32(); - this.readU32(); - this.readU32(); - this.readU32(); + this.readU32() + this.readU32() + this.readU32() + this.readU32() // const line = this.readU32(); // const commentRef = this.readU32(); @@ -499,7 +497,7 @@ export class BinaryXmlParser { // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0 // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0 - return null; + return null } readXmlElementStart(/* header */): any { @@ -511,47 +509,46 @@ export class BinaryXmlParser { nodeName: null, attributes: [], childNodes: [], - }; + } - this.readU32(); - this.readU32(); + this.readU32() + this.readU32() // const line = this.readU32(); // const commentRef = this.readU32(); - const nsRef = this.readS32(); - const nameRef = this.readS32(); + const nsRef = this.readS32() + const nameRef = this.readS32() - if (nsRef > 0) { - node.namespaceURI = this.strings[nsRef]; - } + if (nsRef > 0) + node.namespaceURI = this.strings[nsRef] - node.nodeName = this.strings[nameRef]; + node.nodeName = this.strings[nameRef] - this.readU16(); - this.readU16(); + this.readU16() + this.readU16() // const attrStart = this.readU16(); // const attrSize = this.readU16(); - const attrCount = this.readU16(); + const attrCount = this.readU16() // const idIndex = this.readU16(); // const classIndex = this.readU16(); // const styleIndex = this.readU16(); - this.readU16(); - this.readU16(); - this.readU16(); + this.readU16() + this.readU16() + this.readU16() - for (let i = 0; i < attrCount; ++i) { - node.attributes.push(this.readXmlAttribute()); - } + for (let i = 0; i < attrCount; ++i) + node.attributes.push(this.readXmlAttribute()) if (this.document) { - this.parent.childNodes.push(node); - this.parent = node; - } else { - this.document = this.parent = node; + this.parent.childNodes.push(node) + this.parent = node + } + else { + this.document = this.parent = node } - this.stack.push(node); + this.stack.push(node) - return node; + return node } readXmlAttribute(): any { @@ -564,43 +561,41 @@ export class BinaryXmlParser { name: null, value: null, typedValue: null, - }; + } - const nsRef = this.readS32(); - const nameRef = this.readS32(); - const valueRef = this.readS32(); + const nsRef = this.readS32() + const nameRef = this.readS32() + const valueRef = this.readS32() - if (nsRef > 0) { - attr.namespaceURI = this.strings[nsRef]; - } + if (nsRef > 0) + attr.namespaceURI = this.strings[nsRef] - attr.nodeName = attr.name = this.strings[nameRef]; + attr.nodeName = attr.name = this.strings[nameRef] - if (valueRef > 0) { - attr.value = this.strings[valueRef]; - } + if (valueRef > 0) + attr.value = this.strings[valueRef] - attr.typedValue = this.readTypedValue(); + attr.typedValue = this.readTypedValue() - return attr; + return attr } readXmlElementEnd(/* header */): null { // debug('readXmlCData'); - this.readU32(); - this.readU32(); - this.readU32(); - this.readU32(); + this.readU32() + this.readU32() + this.readU32() + this.readU32() // const line = this.readU32(); // const commentRef = this.readU32(); // const nsRef = this.readS32(); // const nameRef = this.readS32(); - this.stack.pop(); - this.parent = this.stack[this.stack.length - 1]; + this.stack.pop() + this.parent = this.stack[this.stack.length - 1] - return null; + return null } readXmlCData(/* header */): any { @@ -612,74 +607,72 @@ export class BinaryXmlParser { nodeName: '#cdata', data: null, typedValue: null, - }; + } - this.readU32(); - this.readU32(); + this.readU32() + this.readU32() // const line = this.readU32(); // const commentRef = this.readU32(); - const dataRef = this.readS32(); + const dataRef = this.readS32() - if (dataRef > 0) { - cdata.data = this.strings[dataRef]; - } + if (dataRef > 0) + cdata.data = this.strings[dataRef] - cdata.typedValue = this.readTypedValue(); + cdata.typedValue = this.readTypedValue() - this.parent.childNodes.push(cdata); + this.parent.childNodes.push(cdata) - return cdata; + return cdata } readNull(header: any): null { // debug('readNull'); - this.cursor += header.chunkSize - header.headerSize; - return null; + this.cursor += header.chunkSize - header.headerSize + return null } parse(): any { // debug('parse'); - const xmlHeader = this.readChunkHeader(); - if (xmlHeader.chunkType !== ChunkType.XML) { - throw new Exception('Invalid XML header'); - } + const xmlHeader = this.readChunkHeader() + if (xmlHeader.chunkType !== ChunkType.XML) + throw new Exception('Invalid XML header') while (this.cursor < this.buffer.length) { // debug('chunk'); - const start = this.cursor; - const header = this.readChunkHeader(); + const start = this.cursor + const header = this.readChunkHeader() switch (header.chunkType) { case ChunkType.STRING_POOL: - this.readStringPool(header); - break; + this.readStringPool(header) + break case ChunkType.XML_RESOURCE_MAP: - this.readResourceMap(header); - break; + this.readResourceMap(header) + break case ChunkType.XML_START_NAMESPACE: - this.readXmlNamespaceStart(); - break; + this.readXmlNamespaceStart() + break case ChunkType.XML_END_NAMESPACE: - this.readXmlNamespaceEnd(); - break; + this.readXmlNamespaceEnd() + break case ChunkType.XML_START_ELEMENT: - this.readXmlElementStart(); - break; + this.readXmlElementStart() + break case ChunkType.XML_END_ELEMENT: - this.readXmlElementEnd(); - break; + this.readXmlElementEnd() + break case ChunkType.XML_CDATA: - this.readXmlCData(); - break; + this.readXmlCData() + break case ChunkType.NULL: - this.readNull(header); - break; + this.readNull(header) + break default: - throw new Exception(`Unsupported chunk type '${header.chunkType}'`); + throw new Exception(`Unsupported chunk type '${header.chunkType}'`) } // Ensure we consume the whole chunk - const end = start + header.chunkSize; + const end = start + header.chunkSize if (this.cursor !== end) { // const diff = end - this.cursor; // const type = header.chunkType.toString(16); @@ -690,6 +683,6 @@ export class BinaryXmlParser { } } - return this.document; + return this.document } } diff --git a/src/android/utils/emulator.ts b/src/android/utils/emulator.ts index 71420fb..d6a3930 100644 --- a/src/android/utils/emulator.ts +++ b/src/android/utils/emulator.ts @@ -1,11 +1,11 @@ -import { readFile } from '@ionic/utils-fs'; -import { spawn } from 'child_process'; -import * as Debug from 'debug'; -import * as net from 'net'; -import * as os from 'os'; -import * as path from 'path'; -import * as split2 from 'split2'; -import * as through2 from 'through2'; +import { spawn } from 'node:child_process' +import net from 'node:net' +import os from 'node:os' +import path from 'node:path' +import Debug from 'debug' +import { readFile } from '@ionic/utils-fs' +import split2 from 'split2' +import through2 from 'through2' import { ERR_ALREADY_RUNNING, @@ -13,16 +13,16 @@ import { ERR_NON_ZERO_EXIT, ERR_UNKNOWN_AVD, EmulatorException, -} from '../../errors'; -import { once } from '../../utils/fn'; +} from '../../errors' +import { once } from '../../utils/fn' -import type { Device } from './adb'; -import { getDevices, waitForDevice } from './adb'; -import type { AVD } from './avd'; -import type { SDK } from './sdk'; -import { getSDKPackage, supplementProcessEnv } from './sdk'; +import type { Device } from './adb' +import { getDevices, waitForDevice } from './adb' +import type { AVD } from './avd' +import type { SDK } from './sdk' +import { getSDKPackage, supplementProcessEnv } from './sdk' -const modulePrefix = 'native-run:android:utils:emulator'; +const modulePrefix = 'native-run:android:utils:emulator' /** * Resolves when emulator is ready and running with the specified AVD. @@ -33,22 +33,27 @@ export async function runEmulator( port: number, ): Promise { try { - await spawnEmulator(sdk, avd, port); - } catch (e) { - if (!(e instanceof EmulatorException) || e.code !== ERR_ALREADY_RUNNING) { - throw e; - } + await spawnEmulator(sdk, avd, port) + } + catch (e) { + if (!(e instanceof EmulatorException) || e.code !== ERR_ALREADY_RUNNING) + throw e } - const serial = `emulator-${port}`; - const devices = await getDevices(sdk); - const emulator = devices.find(device => device.serial === serial); + const serial = `emulator-${port}` + const devices = await getDevices(sdk) + const emulator = devices.find(device => device.serial === serial) - if (!emulator) { - throw new EmulatorException(`Emulator not found: ${serial}`); - } + if (!emulator) + throw new EmulatorException(`Emulator not found: ${serial}`) - return emulator; + return emulator +} + +export enum EmulatorEvent { + UnknownAVD, // AVD name was invalid + AlreadyRunning, // already running with current AVD + AVDHomeNotFound, // Cannot find AVD system path } export async function spawnEmulator( @@ -56,39 +61,45 @@ export async function spawnEmulator( avd: AVD, port: number, ): Promise { - const debug = Debug(`${modulePrefix}:${spawnEmulator.name}`); - const emulator = await getSDKPackage(path.join(sdk.root, 'emulator')); - const emulatorBin = path.join(emulator.location, 'emulator'); - const args = ['-avd', avd.id, '-port', port.toString(), '-verbose']; - debug('Invoking emulator: %O %O', emulatorBin, args); + const debug = Debug(`${modulePrefix}:${spawnEmulator.name}`) + const emulator = await getSDKPackage(path.join(sdk.root, 'emulator')) + const emulatorBin = path.join(emulator.location, 'emulator') + const args = ['-avd', avd.id, '-port', port.toString(), '-verbose'] + debug('Invoking emulator: %O %O', emulatorBin, args) const p = spawn(emulatorBin, args, { detached: true, stdio: ['ignore', 'pipe', 'pipe'], env: supplementProcessEnv(sdk), - }); - p.unref(); + }) + p.unref() return new Promise((_resolve, _reject) => { + const cleanup = () => { + debug('Unhooking stdout/stderr streams from emulator process') + p.stdout.push(null) + p.stderr.push(null) + } + const resolve: typeof _resolve = once(() => { - _resolve(); - cleanup(); - }); - const reject: typeof _reject = once(err => { - _reject(err); - cleanup(); - }); + _resolve() + cleanup() + }) + const reject: typeof _reject = once((err) => { + _reject(err) + cleanup() + }) waitForDevice(sdk, `emulator-${port}`).then( () => resolve(), err => reject(err), - ); + ) const eventParser = through2((chunk: string, enc, cb) => { - const line = chunk.toString(); + const line = chunk.toString() - debug('Android Emulator: %O', line); - const event = parseEmulatorOutput(line); + debug('Android Emulator: %O', line) + const event = parseEmulatorOutput(line) if (event === EmulatorEvent.AlreadyRunning) { reject( @@ -96,40 +107,36 @@ export async function spawnEmulator( `Emulator already running with AVD [${avd.id}]`, ERR_ALREADY_RUNNING, ), - ); - } else if (event === EmulatorEvent.UnknownAVD) { + ) + } + else if (event === EmulatorEvent.UnknownAVD) { reject( new EmulatorException( `Unknown AVD name [${avd.id}]`, ERR_UNKNOWN_AVD, ), - ); - } else if (event === EmulatorEvent.AVDHomeNotFound) { + ) + } + else if (event === EmulatorEvent.AVDHomeNotFound) { reject( new EmulatorException( - `Emulator cannot find AVD home`, + 'Emulator cannot find AVD home', ERR_AVD_HOME_NOT_FOUND, ), - ); + ) } - cb(); - }); + cb() + }) - const stdoutStream = p.stdout.pipe(split2()); - const stderrStream = p.stderr.pipe(split2()); + const stdoutStream = p.stdout.pipe(split2()) + const stderrStream = p.stderr.pipe(split2()) - stdoutStream.pipe(eventParser); - stderrStream.pipe(eventParser); + stdoutStream.pipe(eventParser) + stderrStream.pipe(eventParser) - const cleanup = () => { - debug('Unhooking stdout/stderr streams from emulator process'); - p.stdout.push(null); - p.stderr.push(null); - }; - - p.on('close', code => { - debug('Emulator closed, exit code %d', code); + p.on('close', (code: number) => { + debug('Emulator closed, exit code %d', code) if (code > 0) { reject( @@ -137,75 +144,67 @@ export async function spawnEmulator( `Non-zero exit code from Emulator: ${code}`, ERR_NON_ZERO_EXIT, ), - ); + ) } - }); - - p.on('error', err => { - debug('Emulator error: %O', err); - reject(err); - }); - }); -} + }) -export enum EmulatorEvent { - UnknownAVD, // AVD name was invalid - AlreadyRunning, // already running with current AVD - AVDHomeNotFound, // Cannot find AVD system path + p.on('error', (err) => { + debug('Emulator error: %O', err) + reject(err) + }) + }) } export function parseEmulatorOutput(line: string): EmulatorEvent | undefined { - const debug = Debug(`${modulePrefix}:${parseEmulatorOutput.name}`); - let event: EmulatorEvent | undefined; + const debug = Debug(`${modulePrefix}:${parseEmulatorOutput.name}`) + let event: EmulatorEvent | undefined - if (line.includes('Unknown AVD name')) { - event = EmulatorEvent.UnknownAVD; - } else if ( + if (line.includes('Unknown AVD name')) + event = EmulatorEvent.UnknownAVD + else if ( line.includes('another emulator instance running with the current AVD') - ) { - event = EmulatorEvent.AlreadyRunning; - } else if (line.includes('Cannot find AVD system path')) { - event = EmulatorEvent.AVDHomeNotFound; - } + ) + event = EmulatorEvent.AlreadyRunning + else if (line.includes('Cannot find AVD system path')) + event = EmulatorEvent.AVDHomeNotFound - if (typeof event !== 'undefined') { - debug('Parsed event from emulator output: %s', EmulatorEvent[event]); - } + if (typeof event !== 'undefined') + debug('Parsed event from emulator output: %s', EmulatorEvent[event]) - return event; + return event } export async function getAVDFromEmulator( emulator: Device, avds: readonly AVD[], ): Promise { - const debug = Debug(`${modulePrefix}:${getAVDFromEmulator.name}`); - const emulatorPortRegex = /^emulator-(\d+)$/; - const m = emulator.serial.match(emulatorPortRegex); + const debug = Debug(`${modulePrefix}:${getAVDFromEmulator.name}`) + const emulatorPortRegex = /^emulator-(\d+)$/ + const m = emulator.serial.match(emulatorPortRegex) if (!m) { throw new EmulatorException( `Emulator ${emulator.serial} does not match expected emulator serial format`, - ); + ) } - const port = Number.parseInt(m[1], 10); - const host = 'localhost'; - const sock = net.createConnection({ host, port }); - sock.setEncoding('utf8'); - sock.setTimeout(5000); + const port = Number.parseInt(m[1], 10) + const host = 'localhost' + const sock = net.createConnection({ host, port }) + sock.setEncoding('utf8') + sock.setTimeout(5000) const readAuthFile = new Promise((resolve, reject) => { sock.on('connect', () => { - debug('Connected to %s:%d', host, port); + debug('Connected to %s:%d', host, port) readFile(path.resolve(os.homedir(), '.emulator_console_auth_token'), { encoding: 'utf8', }).then( contents => resolve(contents.trim()), err => reject(err), - ); - }); - }); + ) + }) + }) enum Stage { Initial, @@ -216,82 +215,86 @@ export async function getAVDFromEmulator( } return new Promise((resolve, reject) => { - let stage = Stage.Initial; + let stage = Stage.Initial const timer = setTimeout(() => { if (stage !== Stage.Complete) { reject( new EmulatorException( - `Took too long to get AVD name from Android Emulator Console, something went wrong.`, + 'Took too long to get AVD name from Android Emulator Console, something went wrong.', ), - ); + ) } - }, 3000); + }, 3000) const cleanup = once(() => { - clearTimeout(timer); - sock.end(); - }); + clearTimeout(timer) + sock.end() + }) sock.on('timeout', () => { - reject(new EmulatorException(`Socket timeout on ${host}:${port}`)); - cleanup(); - }); + reject(new EmulatorException(`Socket timeout on ${host}:${port}`)) + cleanup() + }) sock.pipe(split2()).pipe( through2((chunk: string, enc, cb) => { - const line = chunk.toString(); + const line = chunk.toString() - debug('Android Console: %O', line); + debug('Android Console: %O', line) if ( - stage === Stage.Initial && - line.includes('Authentication required') + stage === Stage.Initial + && line.includes('Authentication required') ) { - stage = Stage.Auth; - } else if (stage === Stage.Auth && line.trim() === 'OK') { + stage = Stage.Auth + } + else if (stage === Stage.Auth && line.trim() === 'OK') { readAuthFile.then( token => sock.write(`auth ${token}\n`, 'utf8'), err => reject(err), - ); - stage = Stage.AuthSuccess; - } else if (stage === Stage.AuthSuccess && line.trim() === 'OK') { - sock.write('avd name\n', 'utf8'); - stage = Stage.Response; - } else if (stage === Stage.Response) { - const avdId = line.trim(); - const avd = avds.find(avd => avd.id === avdId); + ) + stage = Stage.AuthSuccess + } + else if (stage === Stage.AuthSuccess && line.trim() === 'OK') { + sock.write('avd name\n', 'utf8') + stage = Stage.Response + } + else if (stage === Stage.Response) { + const avdId = line.trim() + const avd = avds.find(avd => avd.id === avdId) if (avd) { - resolve(avd); - } else { + resolve(avd) + } + else { reject( new EmulatorException( `Unknown AVD name [${avdId}]`, ERR_UNKNOWN_AVD, ), - ); + ) } - stage = Stage.Complete; - cleanup(); + stage = Stage.Complete + cleanup() } - cb(); + cb() }), - ); - }); + ) + }) } export function parseAndroidConsoleResponse( output: string, ): string | undefined { - const debug = Debug(`${modulePrefix}:${parseAndroidConsoleResponse.name}`); - const m = /([\s\S]+)OK\r?\n/g.exec(output); + const debug = Debug(`${modulePrefix}:${parseAndroidConsoleResponse.name}`) + const m = /([\s\S]+)OK\r?\n/g.exec(output) if (m) { - const [, response] = m; - debug('Parsed response data from Android Console output: %O', response); - return response; + const [, response] = m + debug('Parsed response data from Android Console output: %O', response) + return response } } diff --git a/src/android/utils/list.ts b/src/android/utils/list.ts index d5e5558..8d1e257 100644 --- a/src/android/utils/list.ts +++ b/src/android/utils/list.ts @@ -1,26 +1,25 @@ -import type { Target } from '../../utils/list'; +import type { Target } from '../../utils/list' -import type { Device } from './adb'; -import { getDevices } from './adb'; -import type { AVD } from './avd'; -import { getDefaultAVD, getInstalledAVDs } from './avd'; -import type { SDK } from './sdk'; +import type { Device } from './adb' +import { getDevices } from './adb' +import type { AVD } from './avd' +import { getDefaultAVD, getInstalledAVDs } from './avd' +import type { SDK } from './sdk' export async function getDeviceTargets(sdk: SDK): Promise { return (await getDevices(sdk)) .filter(device => device.type === 'hardware') - .map(deviceToTarget); + .map(deviceToTarget) } export async function getVirtualTargets(sdk: SDK): Promise { - const avds = await getInstalledAVDs(sdk); - const defaultAvd = await getDefaultAVD(sdk, avds); + const avds = await getInstalledAVDs(sdk) + const defaultAvd = await getDefaultAVD(sdk, avds) - if (!avds.includes(defaultAvd)) { - avds.push(defaultAvd); - } + if (!avds.includes(defaultAvd)) + avds.push(defaultAvd) - return avds.map(avdToTarget); + return avds.map(avdToTarget) } export function deviceToTarget(device: Device): Target { @@ -29,7 +28,7 @@ export function deviceToTarget(device: Device): Target { model: `${device.manufacturer} ${device.model}`, sdkVersion: device.sdkVersion, id: device.serial, - }; + } } export function avdToTarget(avd: AVD): Target { @@ -38,5 +37,5 @@ export function avdToTarget(avd: AVD): Target { name: avd.name, sdkVersion: avd.sdkVersion, id: avd.id, - }; + } } diff --git a/src/android/utils/run.ts b/src/android/utils/run.ts index ed75a81..c1084d4 100644 --- a/src/android/utils/run.ts +++ b/src/android/utils/run.ts @@ -1,20 +1,20 @@ -import * as Debug from 'debug'; +import Debug from 'debug' import { ADBException, ERR_INCOMPATIBLE_UPDATE, ERR_VERSION_DOWNGRADE, -} from '../../errors'; -import { log } from '../../utils/log'; +} from '../../errors' +import { log } from '../../utils/log' -import type { Device } from './adb'; -import { installApk, uninstallApp } from './adb'; -import type { AVD } from './avd'; -import { getDefaultAVD } from './avd'; -import { getAVDFromEmulator, runEmulator } from './emulator'; -import type { SDK } from './sdk'; +import type { Device } from './adb' +import { installApk, uninstallApp } from './adb' +import type { AVD } from './avd' +import { getDefaultAVD } from './avd' +import { getAVDFromEmulator, runEmulator } from './emulator' +import type { SDK } from './sdk' -const modulePrefix = 'native-run:android:utils:run'; +const modulePrefix = 'native-run:android:utils:run' export async function selectDeviceByTarget( sdk: SDK, @@ -22,74 +22,74 @@ export async function selectDeviceByTarget( avds: readonly AVD[], target: string, ): Promise { - const debug = Debug(`${modulePrefix}:${selectDeviceByTarget.name}`); + const debug = Debug(`${modulePrefix}:${selectDeviceByTarget.name}`) - debug('--target %s detected', target); - debug('Checking if device can be found by serial: %s', target); - const device = devices.find(d => d.serial === target); + debug('--target %s detected', target) + debug('Checking if device can be found by serial: %s', target) + const device = devices.find(d => d.serial === target) if (device) { - debug('Device found by serial: %s', device.serial); - return device; + debug('Device found by serial: %s', device.serial) + return device } - const emulatorDevices = devices.filter(d => d.type === 'emulator'); + const emulatorDevices = devices.filter(d => d.type === 'emulator') const pairAVD = async ( emulator: Device, ): Promise<[Device, AVD | undefined]> => { - let avd: AVD | undefined; + let avd: AVD | undefined try { - avd = await getAVDFromEmulator(emulator, avds); - debug('Emulator %s is using AVD: %s', emulator.serial, avd.id); - } catch (e) { - debug('Error with emulator %s: %O', emulator.serial, e); + avd = await getAVDFromEmulator(emulator, avds) + debug('Emulator %s is using AVD: %s', emulator.serial, avd.id) + } + catch (e) { + debug('Error with emulator %s: %O', emulator.serial, e) } - return [emulator, avd]; - }; + return [emulator, avd] + } debug( 'Checking if any of %d running emulators are using AVD by ID: %s', emulatorDevices.length, target, - ); + ) const emulatorsAndAVDs = await Promise.all( emulatorDevices.map(emulator => pairAVD(emulator)), - ); + ) const emulators = emulatorsAndAVDs.filter( (t): t is [Device, AVD] => typeof t[1] !== 'undefined', - ); - const emulator = emulators.find(([, avd]) => avd.id === target); + ) + const emulator = emulators.find(([, avd]) => avd.id === target) if (emulator) { - const [device, avd] = emulator; - debug('Emulator %s found by AVD: %s', device.serial, avd.id); - return device; + const [device, avd] = emulator + debug('Emulator %s found by AVD: %s', device.serial, avd.id) + return device } - debug('Checking if AVD can be found by ID: %s', target); - const avd = avds.find(avd => avd.id === target); + debug('Checking if AVD can be found by ID: %s', target) + const avd = avds.find(avd => avd.id === target) if (avd) { - debug('AVD found by ID: %s', avd.id); - const device = await runEmulator(sdk, avd, 5554); // TODO: 5554 will not always be available at this point - debug('Emulator ready, running avd: %s on %s', avd.id, device.serial); + debug('AVD found by ID: %s', avd.id) + const device = await runEmulator(sdk, avd, 5554) // TODO: 5554 will not always be available at this point + debug('Emulator ready, running avd: %s on %s', avd.id, device.serial) - return device; + return device } } export async function selectHardwareDevice( devices: readonly Device[], ): Promise { - const hardwareDevices = devices.filter(d => d.type === 'hardware'); + const hardwareDevices = devices.filter(d => d.type === 'hardware') // If a hardware device is found, we prefer launching to it instead of in an emulator. - if (hardwareDevices.length > 0) { - return hardwareDevices[0]; // TODO: can probably do better analysis on which to use? - } + if (hardwareDevices.length > 0) + return hardwareDevices[0] // TODO: can probably do better analysis on which to use? } export async function selectVirtualDevice( @@ -97,22 +97,22 @@ export async function selectVirtualDevice( devices: readonly Device[], avds: readonly AVD[], ): Promise { - const debug = Debug(`${modulePrefix}:${selectVirtualDevice.name}`); - const emulators = devices.filter(d => d.type === 'emulator'); + const debug = Debug(`${modulePrefix}:${selectVirtualDevice.name}`) + const emulators = devices.filter(d => d.type === 'emulator') // If an emulator is running, use it. if (emulators.length > 0) { - const [emulator] = emulators; - debug('Found running emulator: %s', emulator.serial); - return emulator; + const [emulator] = emulators + debug('Found running emulator: %s', emulator.serial) + return emulator } // Spin up an emulator using the AVD we ship with. - const defaultAvd = await getDefaultAVD(sdk, avds); - const device = await runEmulator(sdk, defaultAvd, 5554); // TODO: will 5554 always be available at this point? - debug('Emulator ready, running avd: %s on %s', defaultAvd.id, device.serial); + const defaultAvd = await getDefaultAVD(sdk, avds) + const device = await runEmulator(sdk, defaultAvd, 5554) // TODO: will 5554 always be available at this point? + debug('Emulator ready, running avd: %s on %s', defaultAvd.id, device.serial) - return device; + return device } export async function installApkToDevice( @@ -121,23 +121,24 @@ export async function installApkToDevice( apk: string, appId: string, ): Promise { - log(`Installing ${apk}...\n`); + log(`Installing ${apk}...\n`) try { - await installApk(sdk, device, apk); - } catch (e) { + await installApk(sdk, device, apk) + } + catch (e) { if (e instanceof ADBException) { if ( - e.code === ERR_INCOMPATIBLE_UPDATE || - e.code === ERR_VERSION_DOWNGRADE + e.code === ERR_INCOMPATIBLE_UPDATE + || e.code === ERR_VERSION_DOWNGRADE ) { - log(`${e.message} Uninstalling and trying again...\n`); - await uninstallApp(sdk, device, appId); - await installApk(sdk, device, apk); - return; + log(`${e.message} Uninstalling and trying again...\n`) + await uninstallApp(sdk, device, appId) + await installApk(sdk, device, apk) + return } } - throw e; + throw e } } diff --git a/src/android/utils/sdk/api.ts b/src/android/utils/sdk/api.ts index d89d0cc..91d6a69 100644 --- a/src/android/utils/sdk/api.ts +++ b/src/android/utils/sdk/api.ts @@ -1,30 +1,30 @@ -import * as Debug from 'debug'; +import Debug from 'debug' -import type * as Nexus_5X_API_24 from '../../data/avds/Nexus_5X_API_24.json'; -import type * as Pixel_2_API_26 from '../../data/avds/Pixel_2_API_26.json'; -import type * as Pixel_2_API_27 from '../../data/avds/Pixel_2_API_27.json'; -import type * as Pixel_2_API_28 from '../../data/avds/Pixel_2_API_28.json'; -import type * as Pixel_3_API_29 from '../../data/avds/Pixel_3_API_29.json'; -import type * as Pixel_3_API_30 from '../../data/avds/Pixel_3_API_30.json'; -import type * as Pixel_3_API_31 from '../../data/avds/Pixel_3_API_31.json'; -import type * as Pixel_3_API_32 from '../../data/avds/Pixel_3_API_32.json'; -import type * as Pixel_4_API_33 from '../../data/avds/Pixel_4_API_33.json'; -import type * as Pixel_API_25 from '../../data/avds/Pixel_API_25.json'; +import type * as Nexus_5X_API_24 from '../../data/avds/Nexus_5X_API_24.json' +import type * as Pixel_2_API_26 from '../../data/avds/Pixel_2_API_26.json' +import type * as Pixel_2_API_27 from '../../data/avds/Pixel_2_API_27.json' +import type * as Pixel_2_API_28 from '../../data/avds/Pixel_2_API_28.json' +import type * as Pixel_3_API_29 from '../../data/avds/Pixel_3_API_29.json' +import type * as Pixel_3_API_30 from '../../data/avds/Pixel_3_API_30.json' +import type * as Pixel_3_API_31 from '../../data/avds/Pixel_3_API_31.json' +import type * as Pixel_3_API_32 from '../../data/avds/Pixel_3_API_32.json' +import type * as Pixel_4_API_33 from '../../data/avds/Pixel_4_API_33.json' +import type * as Pixel_API_25 from '../../data/avds/Pixel_API_25.json' -import type { SDKPackage } from './'; +import type { SDKPackage } from './' -const modulePrefix = 'native-run:android:utils:sdk:api'; +const modulePrefix = 'native-run:android:utils:sdk:api' export interface APILevel { - readonly apiLevel: string; - readonly packages: SDKPackage[]; - readonly missingPackages?: APISchemaPackage[]; + readonly apiLevel: string + readonly packages: SDKPackage[] + readonly missingPackages?: APISchemaPackage[] } export async function getAPILevels( packages: SDKPackage[], ): Promise { - const debug = Debug(`${modulePrefix}:${getAPILevels.name}`); + const debug = Debug(`${modulePrefix}:${getAPILevels.name}`) const levels = [ ...new Set( packages @@ -33,43 +33,42 @@ export async function getAPILevels( (apiLevel): apiLevel is string => typeof apiLevel !== 'undefined', ), ), - ].sort((a, b) => (a <= b ? 1 : -1)); + ].sort((a, b) => (a <= b ? 1 : -1)) const apis = levels.map(apiLevel => ({ apiLevel, packages: packages.filter(pkg => pkg.apiLevel === apiLevel), - })); + })) debug( 'Discovered installed API Levels: %O', apis.map(api => ({ ...api, packages: api.packages.map(pkg => pkg.path) })), - ); + ) - return apis; + return apis } export function findUnsatisfiedPackages( packages: readonly SDKPackage[], schemas: readonly APISchemaPackage[], ): APISchemaPackage[] { - return schemas.filter(pkg => !findPackageBySchema(packages, pkg)); + return schemas.filter(pkg => !findPackageBySchema(packages, pkg)) } export function findPackageBySchema( packages: readonly SDKPackage[], pkg: APISchemaPackage, ): SDKPackage | undefined { - const apiPkg = findPackageBySchemaPath(packages, pkg.path); + const apiPkg = findPackageBySchemaPath(packages, pkg.path) if (apiPkg) { if (typeof pkg.version === 'string') { - if (pkg.version === apiPkg.version) { - return apiPkg; - } - } else { - if (apiPkg.version.match(pkg.version)) { - return apiPkg; - } + if (pkg.version === apiPkg.version) + return apiPkg + } + else { + if (apiPkg.version.match(pkg.version)) + return apiPkg } } } @@ -78,13 +77,12 @@ export function findPackageBySchemaPath( packages: readonly SDKPackage[], path: string | RegExp, ): SDKPackage | undefined { - return packages.find(pkg => { - if (typeof path !== 'string') { - return !!pkg.path.match(path); - } + return packages.find((pkg) => { + if (typeof path !== 'string') + return !!pkg.path.match(path) - return path === pkg.path; - }); + return path === pkg.path + }) } export type PartialAVDSchematic = @@ -97,18 +95,18 @@ export type PartialAVDSchematic = | typeof Pixel_2_API_27 | typeof Pixel_2_API_26 | typeof Pixel_API_25 - | typeof Nexus_5X_API_24; + | typeof Nexus_5X_API_24 export interface APISchemaPackage { - readonly name: string; - readonly path: string; - readonly version: string | RegExp; + readonly name: string + readonly path: string + readonly version: string | RegExp } export interface APISchema { - readonly apiLevel: string; - readonly validate: (packages: readonly SDKPackage[]) => APISchemaPackage[]; - readonly loadPartialAVDSchematic: () => Promise; + readonly apiLevel: string + readonly validate: (packages: readonly SDKPackage[]) => APISchemaPackage[] + readonly loadPartialAVDSchematic: () => Promise } export const API_LEVEL_33: APISchema = Object.freeze({ @@ -121,23 +119,23 @@ export const API_LEVEL_33: APISchema = Object.freeze({ path: 'platforms;android-33', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-33;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-33;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_4_API_33.json'), -}); +}) export const API_LEVEL_32: APISchema = Object.freeze({ apiLevel: '32', @@ -149,23 +147,23 @@ export const API_LEVEL_32: APISchema = Object.freeze({ path: 'platforms;android-32', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-32;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-32;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_3_API_32.json'), -}); +}) export const API_LEVEL_31: APISchema = Object.freeze({ apiLevel: '31', @@ -177,23 +175,23 @@ export const API_LEVEL_31: APISchema = Object.freeze({ path: 'platforms;android-31', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-31;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-31;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_3_API_31.json'), -}); +}) export const API_LEVEL_30: APISchema = Object.freeze({ apiLevel: '30', @@ -205,23 +203,23 @@ export const API_LEVEL_30: APISchema = Object.freeze({ path: 'platforms;android-30', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-30;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-30;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_3_API_30.json'), -}); +}) export const API_LEVEL_29: APISchema = Object.freeze({ apiLevel: '29', @@ -233,23 +231,23 @@ export const API_LEVEL_29: APISchema = Object.freeze({ path: 'platforms;android-29', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-29;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-29;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_3_API_29.json'), -}); +}) export const API_LEVEL_28: APISchema = Object.freeze({ apiLevel: '28', @@ -261,23 +259,23 @@ export const API_LEVEL_28: APISchema = Object.freeze({ path: 'platforms;android-28', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-28;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-28;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_2_API_28.json'), -}); +}) export const API_LEVEL_27: APISchema = Object.freeze({ apiLevel: '27', @@ -289,23 +287,23 @@ export const API_LEVEL_27: APISchema = Object.freeze({ path: 'platforms;android-27', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-27;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-27;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_2_API_27.json'), -}); +}) export const API_LEVEL_26: APISchema = Object.freeze({ apiLevel: '26', @@ -317,23 +315,23 @@ export const API_LEVEL_26: APISchema = Object.freeze({ path: 'platforms;android-26', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-26;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-26;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_2_API_26.json'), -}); +}) export const API_LEVEL_25: APISchema = Object.freeze({ apiLevel: '25', @@ -345,23 +343,23 @@ export const API_LEVEL_25: APISchema = Object.freeze({ path: 'platforms;android-25', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-25;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-25;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Pixel_API_25.json'), -}); +}) export const API_LEVEL_24: APISchema = Object.freeze({ apiLevel: '24', @@ -373,23 +371,23 @@ export const API_LEVEL_24: APISchema = Object.freeze({ path: 'platforms;android-24', version: /.+/, }, - ]; + ] - const missingPackages = findUnsatisfiedPackages(packages, schemas); + const missingPackages = findUnsatisfiedPackages(packages, schemas) if (!findPackageBySchemaPath(packages, /^system-images;android-24;/)) { missingPackages.push({ name: 'Google Play Intel x86 Atom System Image', path: 'system-images;android-24;google_apis_playstore;x86', version: '/.+/', - }); + }) } - return missingPackages; + return missingPackages }, loadPartialAVDSchematic: async () => import('../../data/avds/Nexus_5X_API_24.json'), -}); +}) export const API_LEVEL_SCHEMAS: readonly APISchema[] = [ API_LEVEL_33, @@ -402,4 +400,4 @@ export const API_LEVEL_SCHEMAS: readonly APISchema[] = [ API_LEVEL_26, API_LEVEL_25, API_LEVEL_24, -]; +] diff --git a/src/android/utils/sdk/index.ts b/src/android/utils/sdk/index.ts index c9683a9..0754448 100644 --- a/src/android/utils/sdk/index.ts +++ b/src/android/utils/sdk/index.ts @@ -1,15 +1,15 @@ -import { mkdirp, readdirp } from '@ionic/utils-fs'; -import * as Debug from 'debug'; -import * as os from 'os'; -import * as pathlib from 'path'; +import * as os from 'node:os' +import * as pathlib from 'node:path' +import { mkdirp, readdirp } from '@ionic/utils-fs' +import Debug from 'debug' import { ERR_EMULATOR_HOME_NOT_FOUND, ERR_SDK_NOT_FOUND, ERR_SDK_PACKAGE_NOT_FOUND, SDKException, -} from '../../../errors'; -import { isDir } from '../../../utils/fs'; +} from '../../../errors' +import { isDir } from '../../../utils/fs' import { getAPILevelFromPackageXml, @@ -17,11 +17,11 @@ import { getPathFromPackageXml, getVersionFromPackageXml, readPackageXml, -} from './xml'; +} from './xml' -const modulePrefix = 'native-run:android:utils:sdk'; +const modulePrefix = 'native-run:android:utils:sdk' -const homedir = os.homedir(); +const homedir = os.homedir() export const SDK_DIRECTORIES: ReadonlyMap< NodeJS.Platform, string[] | undefined @@ -38,47 +38,46 @@ export const SDK_DIRECTORIES: ReadonlyMap< ), ], ], -]); +]) export interface SDK { - readonly root: string; - readonly emulatorHome: string; - readonly avdHome: string; - packages?: SDKPackage[]; + readonly root: string + readonly emulatorHome: string + readonly avdHome: string + packages?: SDKPackage[] } export async function getSDK(): Promise { - const root = await resolveSDKRoot(); - const emulatorHome = await resolveEmulatorHome(); - const avdHome = await resolveAVDHome(); + const root = await resolveSDKRoot() + const emulatorHome = await resolveEmulatorHome() + const avdHome = await resolveAVDHome() - return { root, emulatorHome, avdHome }; + return { root, emulatorHome, avdHome } } export interface SDKPackage { - readonly path: string; - readonly location: string; - readonly version: string; - readonly name: string; - readonly apiLevel?: string; + readonly path: string + readonly location: string + readonly version: string + readonly name: string + readonly apiLevel?: string } -const pkgcache = new Map(); +const pkgcache = new Map() export async function findAllSDKPackages(sdk: SDK): Promise { - const debug = Debug(`${modulePrefix}:${findAllSDKPackages.name}`); + const debug = Debug(`${modulePrefix}:${findAllSDKPackages.name}`) - if (sdk.packages) { - return sdk.packages; - } + if (sdk.packages) + return sdk.packages - const sourcesRe = /^sources\/android-\d+\/.+\/.+/; - debug('Walking %s to discover SDK packages', sdk.root); + const sourcesRe = /^sources\/android-\d+\/.+\/.+/ + debug('Walking %s to discover SDK packages', sdk.root) const contents = await readdirp(sdk.root, { filter: item => pathlib.basename(item.path) === 'package.xml', onError: err => debug('Error while walking SDK: %O', err), walkerOptions: { - pathFilter: p => { + pathFilter: (p) => { if ( [ 'bin', @@ -95,42 +94,40 @@ export async function findAllSDKPackages(sdk: SDK): Promise { 'extras', // 'm2repository', ].includes(pathlib.basename(p)) - ) { - return false; - } + ) + return false - if (p.match(sourcesRe)) { - return false; - } + if (p.match(sourcesRe)) + return false - return true; + return true }, }, - }); + }) sdk.packages = await Promise.all( contents.map(p => pathlib.dirname(p)).map(p => getSDKPackage(p)), - ); + ) - sdk.packages.sort((a, b) => (a.name >= b.name ? 1 : -1)); + sdk.packages.sort((a, b) => (a.name >= b.name ? 1 : -1)) - return sdk.packages; + return sdk.packages } export async function getSDKPackage(location: string): Promise { - const debug = Debug(`${modulePrefix}:${getSDKPackage.name}`); - let pkg = pkgcache.get(location); + const debug = Debug(`${modulePrefix}:${getSDKPackage.name}`) + let pkg = pkgcache.get(location) if (!pkg) { - const packageXmlPath = pathlib.join(location, 'package.xml'); - debug('Parsing %s', packageXmlPath); + const packageXmlPath = pathlib.join(location, 'package.xml') + debug('Parsing %s', packageXmlPath) try { - const packageXml = await readPackageXml(packageXmlPath); - const name = getNameFromPackageXml(packageXml); - const version = getVersionFromPackageXml(packageXml); - const path = getPathFromPackageXml(packageXml); - const apiLevel = getAPILevelFromPackageXml(packageXml); + const packageXml = await readPackageXml(packageXmlPath) + const name = getNameFromPackageXml(packageXml) + const version = getVersionFromPackageXml(packageXml) + const path = getPathFromPackageXml(packageXml) + const apiLevel = getAPILevelFromPackageXml(packageXml) pkg = { path, @@ -138,120 +135,120 @@ export async function getSDKPackage(location: string): Promise { version, name, apiLevel, - }; - } catch (e) { - debug('Encountered error with %s: %O', packageXmlPath, e); + } + } + catch (e) { + debug('Encountered error with %s: %O', packageXmlPath, e) if (e.code === 'ENOENT') { throw new SDKException( `SDK package not found by location: ${location}.`, ERR_SDK_PACKAGE_NOT_FOUND, - ); + ) } - throw e; + throw e } - pkgcache.set(location, pkg); + pkgcache.set(location, pkg) } - return pkg; + return pkg } export async function resolveSDKRoot(): Promise { - const debug = Debug(`${modulePrefix}:${resolveSDKRoot.name}`); - debug('Looking for $ANDROID_HOME'); + const debug = Debug(`${modulePrefix}:${resolveSDKRoot.name}`) + debug('Looking for $ANDROID_HOME') // $ANDROID_HOME is deprecated, but still overrides $ANDROID_SDK_ROOT if // defined and valid. if (process.env.ANDROID_HOME && (await isDir(process.env.ANDROID_HOME))) { - debug('Using $ANDROID_HOME at %s', process.env.ANDROID_HOME); - return process.env.ANDROID_HOME; + debug('Using $ANDROID_HOME at %s', process.env.ANDROID_HOME) + return process.env.ANDROID_HOME } - debug('Looking for $ANDROID_SDK_ROOT'); + debug('Looking for $ANDROID_SDK_ROOT') // No valid $ANDROID_HOME, try $ANDROID_SDK_ROOT. if ( - process.env.ANDROID_SDK_ROOT && - (await isDir(process.env.ANDROID_SDK_ROOT)) + process.env.ANDROID_SDK_ROOT + && (await isDir(process.env.ANDROID_SDK_ROOT)) ) { - debug('Using $ANDROID_SDK_ROOT at %s', process.env.ANDROID_SDK_ROOT); - return process.env.ANDROID_SDK_ROOT; + debug('Using $ANDROID_SDK_ROOT at %s', process.env.ANDROID_SDK_ROOT) + return process.env.ANDROID_SDK_ROOT } - const sdkDirs = SDK_DIRECTORIES.get(process.platform); + const sdkDirs = SDK_DIRECTORIES.get(process.platform) - if (!sdkDirs) { - throw new SDKException(`Unsupported platform: ${process.platform}`); - } + if (!sdkDirs) + throw new SDKException(`Unsupported platform: ${process.platform}`) - debug('Looking at following directories: %O', sdkDirs); + debug('Looking at following directories: %O', sdkDirs) for (const sdkDir of sdkDirs) { if (await isDir(sdkDir)) { - debug('Using %s', sdkDir); - return sdkDir; + debug('Using %s', sdkDir) + return sdkDir } } - throw new SDKException(`No valid Android SDK root found.`, ERR_SDK_NOT_FOUND); + throw new SDKException('No valid Android SDK root found.', ERR_SDK_NOT_FOUND) } export async function resolveEmulatorHome(): Promise { - const debug = Debug(`${modulePrefix}:${resolveEmulatorHome.name}`); - debug('Looking for $ANDROID_EMULATOR_HOME'); + const debug = Debug(`${modulePrefix}:${resolveEmulatorHome.name}`) + debug('Looking for $ANDROID_EMULATOR_HOME') if ( - process.env.ANDROID_EMULATOR_HOME && - (await isDir(process.env.ANDROID_EMULATOR_HOME)) + process.env.ANDROID_EMULATOR_HOME + && (await isDir(process.env.ANDROID_EMULATOR_HOME)) ) { debug( 'Using $ANDROID_EMULATOR_HOME at %s', process.env.$ANDROID_EMULATOR_HOME, - ); - return process.env.ANDROID_EMULATOR_HOME; + ) + return process.env.ANDROID_EMULATOR_HOME } - debug('Looking at $HOME/.android'); + debug('Looking at $HOME/.android') - const homeEmulatorHome = pathlib.join(homedir, '.android'); + const homeEmulatorHome = pathlib.join(homedir, '.android') if (await isDir(homeEmulatorHome)) { - debug('Using $HOME/.android/ at %s', homeEmulatorHome); - return homeEmulatorHome; + debug('Using $HOME/.android/ at %s', homeEmulatorHome) + return homeEmulatorHome } throw new SDKException( - `No valid Android Emulator home found.`, + 'No valid Android Emulator home found.', ERR_EMULATOR_HOME_NOT_FOUND, - ); + ) } export async function resolveAVDHome(): Promise { - const debug = Debug(`${modulePrefix}:${resolveAVDHome.name}`); + const debug = Debug(`${modulePrefix}:${resolveAVDHome.name}`) - debug('Looking for $ANDROID_AVD_HOME'); + debug('Looking for $ANDROID_AVD_HOME') if ( - process.env.ANDROID_AVD_HOME && - (await isDir(process.env.ANDROID_AVD_HOME)) + process.env.ANDROID_AVD_HOME + && (await isDir(process.env.ANDROID_AVD_HOME)) ) { - debug('Using $ANDROID_AVD_HOME at %s', process.env.$ANDROID_AVD_HOME); - return process.env.ANDROID_AVD_HOME; + debug('Using $ANDROID_AVD_HOME at %s', process.env.$ANDROID_AVD_HOME) + return process.env.ANDROID_AVD_HOME } - debug('Looking at $HOME/.android/avd'); + debug('Looking at $HOME/.android/avd') - const homeAvdHome = pathlib.join(homedir, '.android', 'avd'); + const homeAvdHome = pathlib.join(homedir, '.android', 'avd') if (!(await isDir(homeAvdHome))) { - debug('Creating directory: %s', homeAvdHome); - await mkdirp(homeAvdHome); + debug('Creating directory: %s', homeAvdHome) + await mkdirp(homeAvdHome) } - debug('Using $HOME/.android/avd/ at %s', homeAvdHome); - return homeAvdHome; + debug('Using $HOME/.android/avd/ at %s', homeAvdHome) + return homeAvdHome } export function supplementProcessEnv(sdk: SDK): NodeJS.ProcessEnv { @@ -260,5 +257,5 @@ export function supplementProcessEnv(sdk: SDK): NodeJS.ProcessEnv { ANDROID_SDK_ROOT: sdk.root, ANDROID_EMULATOR_HOME: sdk.emulatorHome, ANDROID_AVD_HOME: sdk.avdHome, - }; + } } diff --git a/src/android/utils/sdk/xml.ts b/src/android/utils/sdk/xml.ts index 91d007f..2559d91 100644 --- a/src/android/utils/sdk/xml.ts +++ b/src/android/utils/sdk/xml.ts @@ -1,54 +1,53 @@ -import { readFile } from '@ionic/utils-fs'; -import type { Element, ElementTree } from 'elementtree'; +import { readFile } from '@ionic/utils-fs' +import type { Element, ElementTree } from 'elementtree' -import { ERR_INVALID_SDK_PACKAGE, SDKException } from '../../../errors'; +import { ERR_INVALID_SDK_PACKAGE, SDKException } from '../../../errors' export function getAPILevelFromPackageXml( packageXml: ElementTree, ): string | undefined { - const apiLevel = packageXml.find('./localPackage/type-details/api-level'); + const apiLevel = packageXml.find('./localPackage/type-details/api-level') - return apiLevel?.text?.toString(); + return apiLevel?.text?.toString() } export async function readPackageXml(path: string): Promise { - const et = await import('elementtree'); - const contents = await readFile(path, { encoding: 'utf8' }); - const etree = et.parse(contents); + const et = await import('elementtree') + const contents = await readFile(path, { encoding: 'utf8' }) + const etree = et.parse(contents) - return etree; + return etree } export function getPathFromPackageXml(packageXml: ElementTree): string { - const localPackage = packageXml.find('./localPackage'); + const localPackage = packageXml.find('./localPackage') - if (!localPackage) { - throw new SDKException(`Invalid SDK package.`, ERR_INVALID_SDK_PACKAGE); - } + if (!localPackage) + throw new SDKException('Invalid SDK package.', ERR_INVALID_SDK_PACKAGE) - const path = localPackage.get('path'); + const path = localPackage.get('path') if (!path) { throw new SDKException( - `Invalid SDK package path.`, + 'Invalid SDK package path.', ERR_INVALID_SDK_PACKAGE, - ); + ) } - return path.toString(); + return path.toString() } export function getNameFromPackageXml(packageXml: ElementTree): string { - const name = packageXml.find('./localPackage/display-name'); + const name = packageXml.find('./localPackage/display-name') if (!name || !name.text) { throw new SDKException( - `Invalid SDK package name.`, + 'Invalid SDK package name.', ERR_INVALID_SDK_PACKAGE, - ); + ) } - return name.text.toString(); + return name.text.toString() } export function getVersionFromPackageXml(packageXml: ElementTree): string { @@ -56,26 +55,25 @@ export function getVersionFromPackageXml(packageXml: ElementTree): string { packageXml.find('./localPackage/revision/major'), packageXml.find('./localPackage/revision/minor'), packageXml.find('./localPackage/revision/micro'), - ]; + ] const textFromElement = (e: Element | null): string => - e?.text ? e.text.toString() : ''; - const versions: string[] = []; + e?.text ? e.text.toString() : '' + const versions: string[] = [] for (const version of versionElements.map(textFromElement)) { - if (!version) { - break; - } + if (!version) + break - versions.push(version); + versions.push(version) } if (versions.length === 0) { throw new SDKException( - `Invalid SDK package version.`, + 'Invalid SDK package version.', ERR_INVALID_SDK_PACKAGE, - ); + ) } - return versions.join('.'); + return versions.join('.') } diff --git a/src/constants.ts b/src/constants.ts index 35936d4..086a86c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,3 @@ -import * as pathlib from 'path'; +import * as pathlib from 'node:path' -export const ASSETS_PATH = pathlib.resolve(__dirname, '..', 'assets'); +export const ASSETS_PATH = pathlib.resolve(__dirname, '..', 'assets') diff --git a/src/errors.ts b/src/errors.ts index 508611a..6d33074 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,4 +1,4 @@ -import { stringify } from './utils/json'; +import { stringify } from './utils/json' export const enum ExitCode { GENERAL = 1, @@ -6,19 +6,18 @@ export const enum ExitCode { export class Exception extends Error - implements NodeJS.ErrnoException -{ + implements NodeJS.ErrnoException { constructor( readonly message: string, readonly code?: T, readonly exitCode = ExitCode.GENERAL, readonly data?: D, ) { - super(message); + super(message) } serialize(): string { - return `${this.code ? this.code : 'ERR_UNKNOWN'}: ${this.message}`; + return `${this.code ? this.code : 'ERR_UNKNOWN'}: ${this.message}` } toJSON(): any { @@ -26,7 +25,7 @@ export class Exception error: this.message, code: this.code, ...this.data, - }; + } } } @@ -36,43 +35,43 @@ export class AndroidException< > extends Exception { serialize(): string { return ( - `${super.serialize()}\n\n` + - `\tMore details for this error may be available online:\n\n` + - `\thttps://github.com/ionic-team/native-run/wiki/Android-Errors` - ); + `${super.serialize()}\n\n` + + '\tMore details for this error may be available online:\n\n' + + '\thttps://github.com/ionic-team/native-run/wiki/Android-Errors' + ) } } -export const ERR_BAD_INPUT = 'ERR_BAD_INPUT'; -export const ERR_ALREADY_RUNNING = 'ERR_ALREADY_RUNNING '; -export const ERR_AVD_HOME_NOT_FOUND = 'ERR_AVD_HOME_NOT_FOUND'; -export const ERR_EMULATOR_HOME_NOT_FOUND = 'ERR_EMULATOR_HOME_NOT_FOUND'; -export const ERR_INCOMPATIBLE_UPDATE = 'ERR_INCOMPATIBLE_UPDATE'; -export const ERR_VERSION_DOWNGRADE = 'ERR_VERSION_DOWNGRADE'; -export const ERR_MIN_SDK_VERSION = 'ERR_MIN_SDK_VERSION'; -export const ERR_NO_CERTIFICATES = 'ERR_NO_CERTIFICATES'; -export const ERR_NOT_ENOUGH_SPACE = 'ERR_NOT_ENOUGH_SPACE'; -export const ERR_DEVICE_OFFLINE = 'ERR_DEVICE_OFFLINE'; -export const ERR_INVALID_SDK_PACKAGE = 'ERR_INVALID_SDK_PACKAGE'; -export const ERR_INVALID_SERIAL = 'ERR_INVALID_SERIAL'; -export const ERR_INVALID_SKIN = 'ERR_INVALID_SKIN'; -export const ERR_INVALID_SYSTEM_IMAGE = 'ERR_INVALID_SYSTEM_IMAGE'; -export const ERR_NON_ZERO_EXIT = 'ERR_NON_ZERO_EXIT'; -export const ERR_NO_AVDS_FOUND = 'ERR_NO_AVDS_FOUND'; -export const ERR_MISSING_SYSTEM_IMAGE = 'ERR_MISSING_SYSTEM_IMAGE'; -export const ERR_UNSUITABLE_API_INSTALLATION = - 'ERR_UNSUITABLE_API_INSTALLATION'; -export const ERR_SDK_NOT_FOUND = 'ERR_SDK_NOT_FOUND'; -export const ERR_SDK_PACKAGE_NOT_FOUND = 'ERR_SDK_PACKAGE_NOT_FOUND'; -export const ERR_SDK_UNSATISFIED_PACKAGES = 'ERR_SDK_UNSATISFIED_PACKAGES'; -export const ERR_TARGET_NOT_FOUND = 'ERR_TARGET_NOT_FOUND'; -export const ERR_NO_DEVICE = 'ERR_NO_DEVICE'; -export const ERR_NO_TARGET = 'ERR_NO_TARGET'; -export const ERR_DEVICE_LOCKED = 'ERR_DEVICE_LOCKED'; -export const ERR_UNKNOWN_AVD = 'ERR_UNKNOWN_AVD'; -export const ERR_UNSUPPORTED_API_LEVEL = 'ERR_UNSUPPORTED_API_LEVEL'; - -export type CLIExceptionCode = typeof ERR_BAD_INPUT; +export const ERR_BAD_INPUT = 'ERR_BAD_INPUT' +export const ERR_ALREADY_RUNNING = 'ERR_ALREADY_RUNNING ' +export const ERR_AVD_HOME_NOT_FOUND = 'ERR_AVD_HOME_NOT_FOUND' +export const ERR_EMULATOR_HOME_NOT_FOUND = 'ERR_EMULATOR_HOME_NOT_FOUND' +export const ERR_INCOMPATIBLE_UPDATE = 'ERR_INCOMPATIBLE_UPDATE' +export const ERR_VERSION_DOWNGRADE = 'ERR_VERSION_DOWNGRADE' +export const ERR_MIN_SDK_VERSION = 'ERR_MIN_SDK_VERSION' +export const ERR_NO_CERTIFICATES = 'ERR_NO_CERTIFICATES' +export const ERR_NOT_ENOUGH_SPACE = 'ERR_NOT_ENOUGH_SPACE' +export const ERR_DEVICE_OFFLINE = 'ERR_DEVICE_OFFLINE' +export const ERR_INVALID_SDK_PACKAGE = 'ERR_INVALID_SDK_PACKAGE' +export const ERR_INVALID_SERIAL = 'ERR_INVALID_SERIAL' +export const ERR_INVALID_SKIN = 'ERR_INVALID_SKIN' +export const ERR_INVALID_SYSTEM_IMAGE = 'ERR_INVALID_SYSTEM_IMAGE' +export const ERR_NON_ZERO_EXIT = 'ERR_NON_ZERO_EXIT' +export const ERR_NO_AVDS_FOUND = 'ERR_NO_AVDS_FOUND' +export const ERR_MISSING_SYSTEM_IMAGE = 'ERR_MISSING_SYSTEM_IMAGE' +export const ERR_UNSUITABLE_API_INSTALLATION + = 'ERR_UNSUITABLE_API_INSTALLATION' +export const ERR_SDK_NOT_FOUND = 'ERR_SDK_NOT_FOUND' +export const ERR_SDK_PACKAGE_NOT_FOUND = 'ERR_SDK_PACKAGE_NOT_FOUND' +export const ERR_SDK_UNSATISFIED_PACKAGES = 'ERR_SDK_UNSATISFIED_PACKAGES' +export const ERR_TARGET_NOT_FOUND = 'ERR_TARGET_NOT_FOUND' +export const ERR_NO_DEVICE = 'ERR_NO_DEVICE' +export const ERR_NO_TARGET = 'ERR_NO_TARGET' +export const ERR_DEVICE_LOCKED = 'ERR_DEVICE_LOCKED' +export const ERR_UNKNOWN_AVD = 'ERR_UNKNOWN_AVD' +export const ERR_UNSUPPORTED_API_LEVEL = 'ERR_UNSUPPORTED_API_LEVEL' + +export type CLIExceptionCode = typeof ERR_BAD_INPUT export class CLIException extends Exception {} @@ -83,7 +82,7 @@ export type ADBExceptionCode = | typeof ERR_NO_CERTIFICATES | typeof ERR_NOT_ENOUGH_SPACE | typeof ERR_DEVICE_OFFLINE - | typeof ERR_NON_ZERO_EXIT; + | typeof ERR_NON_ZERO_EXIT export class ADBException extends AndroidException {} @@ -93,7 +92,7 @@ export type AVDExceptionCode = | typeof ERR_UNSUITABLE_API_INSTALLATION | typeof ERR_UNSUPPORTED_API_LEVEL | typeof ERR_SDK_UNSATISFIED_PACKAGES - | typeof ERR_MISSING_SYSTEM_IMAGE; + | typeof ERR_MISSING_SYSTEM_IMAGE export class AVDException extends AndroidException {} @@ -102,7 +101,7 @@ export type EmulatorExceptionCode = | typeof ERR_AVD_HOME_NOT_FOUND | typeof ERR_INVALID_SERIAL | typeof ERR_NON_ZERO_EXIT - | typeof ERR_UNKNOWN_AVD; + | typeof ERR_UNKNOWN_AVD export class EmulatorException extends AndroidException {} @@ -110,7 +109,7 @@ export type AndroidRunExceptionCode = | typeof ERR_NO_AVDS_FOUND | typeof ERR_TARGET_NOT_FOUND | typeof ERR_NO_DEVICE - | typeof ERR_NO_TARGET; + | typeof ERR_NO_TARGET export class AndroidRunException extends AndroidException {} @@ -118,7 +117,7 @@ export type SDKExceptionCode = | typeof ERR_EMULATOR_HOME_NOT_FOUND | typeof ERR_INVALID_SDK_PACKAGE | typeof ERR_SDK_NOT_FOUND - | typeof ERR_SDK_PACKAGE_NOT_FOUND; + | typeof ERR_SDK_PACKAGE_NOT_FOUND export class SDKException extends AndroidException {} @@ -126,16 +125,15 @@ export type IOSRunExceptionCode = | typeof ERR_TARGET_NOT_FOUND | typeof ERR_NO_DEVICE | typeof ERR_NO_TARGET - | typeof ERR_DEVICE_LOCKED; + | typeof ERR_DEVICE_LOCKED export class IOSRunException extends Exception {} -export function serializeError(e = new Error()): string { - const stack = String(e.stack ? e.stack : e); +export function serializeError(e = new Error('Unknown error')): string { + const stack = String(e.stack ? e.stack : e) - if (process.argv.includes('--json')) { - return stringify(e instanceof Exception ? e : { error: stack }); - } + if (process.argv.includes('--json')) + return stringify(e instanceof Exception ? e : { error: stack }) - return (e instanceof Exception ? e.serialize() : stack) + '\n'; + return `${e instanceof Exception ? e.serialize() : stack}\n` } diff --git a/src/help.ts b/src/help.ts index 62db76e..8d5d228 100644 --- a/src/help.ts +++ b/src/help.ts @@ -8,8 +8,8 @@ const help = ` --verbose ............ Print verbose output to stderr --list ............... Print connected devices and virtual devices -`; +` export async function run(args: readonly string[]): Promise { - process.stdout.write(help); + process.stdout.write(help) } diff --git a/src/index.ts b/src/index.ts index 223f46f..e8b86e9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import * as Debug from 'debug'; -import * as path from 'path'; +import * as path from 'node:path' +import Debug from 'debug' import { CLIException, @@ -7,56 +7,60 @@ import { Exception, ExitCode, serializeError, -} from './errors'; +} from './errors' -const debug = Debug('native-run'); +const debug = Debug('native-run') export interface Command { - readonly run: (args: readonly string[]) => Promise; + readonly run: (args: readonly string[]) => Promise } export async function run(): Promise { - const args = process.argv.slice(2); + const args = process.argv.slice(2) if (args.includes('--version')) { - const pkg = await import(path.resolve(__dirname, '../package.json')); - process.stdout.write(pkg.version + '\n'); - return; + const pkg = await import(path.resolve(__dirname, '../package.json')) + process.stdout.write(`${pkg.version}\n`) + return } - let cmd: Command; - const [platform, ...platformArgs] = args; + let cmd: Command + const [platform, ...platformArgs] = args try { if (platform === 'android') { - cmd = await import('./android'); - await cmd.run(platformArgs); - } else if (platform === 'ios') { - cmd = await import('./ios'); - await cmd.run(platformArgs); - } else if (platform === '--list') { - cmd = await import('./list'); - await cmd.run(args); - } else { + cmd = await import('./android') + await cmd.run(platformArgs) + } + else if (platform === 'ios') { + cmd = await import('./ios') + await cmd.run(platformArgs) + } + else if (platform === '--list') { + cmd = await import('./list') + await cmd.run(args) + } + else { if ( - !platform || - platform === 'help' || - args.includes('--help') || - args.includes('-h') || - platform.startsWith('-') + !platform + || platform === 'help' + || args.includes('--help') + || args.includes('-h') + || platform.startsWith('-') ) { - cmd = await import('./help'); - return cmd.run(args); + cmd = await import('./help') + return cmd.run(args) } throw new CLIException( `Unsupported platform: "${platform}"`, ERR_BAD_INPUT, - ); + ) } - } catch (e) { - debug('Caught fatal error: %O', e); - process.exitCode = e instanceof Exception ? e.exitCode : ExitCode.GENERAL; - process.stdout.write(serializeError(e)); + } + catch (e) { + debug('Caught fatal error: %O', e) + process.exitCode = e instanceof Exception ? e.exitCode : ExitCode.GENERAL + process.stdout.write(serializeError(e as any)) } } diff --git a/src/ios/help.ts b/src/ios/help.ts index b852967..4141795 100644 --- a/src/ios/help.ts +++ b/src/ios/help.ts @@ -25,8 +25,8 @@ const help = ` With --list prints available simulators --target ........ Use a specific target --connect ............ Tie process to app process -`; +` export async function run(): Promise { - process.stdout.write(`${help}\n`); + process.stdout.write(`${help}\n`) } diff --git a/src/ios/index.ts b/src/ios/index.ts index 0fb5fca..7a5daa1 100644 --- a/src/ios/index.ts +++ b/src/ios/index.ts @@ -1,18 +1,18 @@ -import type { Command } from '../'; +import type { Command } from '../' export async function run(args: readonly string[]): Promise { - let cmd: Command; + let cmd: Command if (args.includes('--help') || args.includes('-h')) { - cmd = await import('./help'); - return cmd.run(args); + cmd = await import('./help') + return cmd.run(args) } if (args.includes('--list') || args.includes('-l')) { - cmd = await import('./list'); - return cmd.run(args); + cmd = await import('./list') + return cmd.run(args) } - cmd = await import('./run'); - await cmd.run(args); + cmd = await import('./run') + await cmd.run(args) } diff --git a/src/ios/lib/client/afc.ts b/src/ios/lib/client/afc.ts index c086e16..27c2ceb 100644 --- a/src/ios/lib/client/afc.ts +++ b/src/ios/lib/client/afc.ts @@ -1,165 +1,166 @@ -import * as Debug from 'debug'; -import * as fs from 'fs'; -import type * as net from 'net'; -import * as path from 'path'; -import { promisify } from 'util'; +import * as fs from 'node:fs' +import type * as net from 'node:net' +import * as path from 'node:path' +import { promisify } from 'node:util' +import Debug from 'debug' -import type { AFCError, AFCResponse } from '../protocol/afc'; +import type { AFCError, AFCResponse } from '../protocol/afc' import { AFCProtocolClient, AFC_FILE_OPEN_FLAGS, AFC_OPS, AFC_STATUS, -} from '../protocol/afc'; +} from '../protocol/afc' -import { ServiceClient } from './client'; +import { ServiceClient } from './client' -const debug = Debug('native-run:ios:lib:client:afc'); -const MAX_OPEN_FILES = 240; +const debug = Debug('native-run:ios:lib:client:afc') +const MAX_OPEN_FILES = 240 export class AFCClient extends ServiceClient { constructor(public socket: net.Socket) { - super(socket, new AFCProtocolClient(socket)); + super(socket, new AFCProtocolClient(socket)) } async getFileInfo(path: string): Promise { - debug(`getFileInfo: ${path}`); + debug(`getFileInfo: ${path}`) const resp = await this.protocolClient.sendMessage({ operation: AFC_OPS.GET_FILE_INFO, data: toCString(path), - }); + }) - const strings: string[] = []; - let currentString = ''; - const tokens = resp.data; - tokens.forEach(token => { + const strings: string[] = [] + let currentString = '' + const tokens = resp.data + tokens.forEach((token) => { if (token === 0) { - strings.push(currentString); - currentString = ''; - } else { - currentString += String.fromCharCode(token); + strings.push(currentString) + currentString = '' } - }); - return strings; + else { + currentString += String.fromCharCode(token) + } + }) + return strings } async writeFile(fd: Buffer, data: Buffer): Promise { - debug(`writeFile: ${Array.prototype.toString.call(fd)}`); + debug(`writeFile: ${Array.prototype.toString.call(fd)}`) return this.protocolClient.sendMessage({ operation: AFC_OPS.FILE_WRITE, data: fd, payload: data, - }); + }) } async openFile(path: string): Promise { - debug(`openFile: ${path}`); + debug(`openFile: ${path}`) // mode + path + null terminator - const data = Buffer.alloc(8 + path.length + 1); + const data = Buffer.alloc(8 + path.length + 1) // write mode - data.writeUInt32LE(AFC_FILE_OPEN_FLAGS.WRONLY, 0); + data.writeUInt32LE(AFC_FILE_OPEN_FLAGS.WRONLY, 0) // then path to file - toCString(path).copy(data, 8); + toCString(path).copy(data, 8) const resp = await this.protocolClient.sendMessage({ operation: AFC_OPS.FILE_OPEN, data, - }); + }) - if (resp.operation === AFC_OPS.FILE_OPEN_RES) { - return resp.data; - } + if (resp.operation === AFC_OPS.FILE_OPEN_RES) + return resp.data throw new Error( `There was an unknown error opening file ${path}, response: ${Array.prototype.toString.call( resp.data, )}`, - ); + ) } async closeFile(fd: Buffer): Promise { - debug(`closeFile fd: ${Array.prototype.toString.call(fd)}`); + debug(`closeFile fd: ${Array.prototype.toString.call(fd)}`) return this.protocolClient.sendMessage({ operation: AFC_OPS.FILE_CLOSE, data: fd, - }); + }) } async uploadFile(srcPath: string, destPath: string): Promise { - debug(`uploadFile: ${srcPath}`); + debug(`uploadFile: ${srcPath}`) // read local file and get fd of destination const [srcFile, destFile] = await Promise.all([ await promisify(fs.readFile)(srcPath), await this.openFile(destPath), - ]); + ]) try { - await this.writeFile(destFile, srcFile); - await this.closeFile(destFile); - } catch (err) { - await this.closeFile(destFile); - throw err; + await this.writeFile(destFile, srcFile) + await this.closeFile(destFile) + } + catch (err) { + await this.closeFile(destFile) + throw err } } async makeDirectory(path: string): Promise { - debug(`makeDirectory: ${path}`); + debug(`makeDirectory: ${path}`) return this.protocolClient.sendMessage({ operation: AFC_OPS.MAKE_DIR, data: toCString(path), - }); + }) } async uploadDirectory(srcPath: string, destPath: string): Promise { - debug(`uploadDirectory: ${srcPath}`); - await this.makeDirectory(destPath); + debug(`uploadDirectory: ${srcPath}`) + await this.makeDirectory(destPath) // AFC doesn't seem to give out more than 240 file handles, // so we delay any requests that would push us over until more open up - let numOpenFiles = 0; - const pendingFileUploads: (() => void)[] = []; - const _this = this; - return uploadDir(srcPath); + let numOpenFiles = 0 + const pendingFileUploads: (() => void)[] = [] + const _this = this // eslint-disable-line @typescript-eslint/no-this-alias + return uploadDir(srcPath) async function uploadDir(dirPath: string): Promise { - const promises: Promise[] = []; + const promises: Promise[] = [] for (const file of fs.readdirSync(dirPath)) { - const filePath = path.join(dirPath, file); + const filePath = path.join(dirPath, file) const remotePath = path.join( destPath, path.relative(srcPath, filePath), - ); + ) if (fs.lstatSync(filePath).isDirectory()) { promises.push( _this.makeDirectory(remotePath).then(() => uploadDir(filePath)), - ); - } else { + ) + } + else { // Create promise to add to promises array // this way it can be resolved once a pending upload has finished - let resolve: (val?: any) => void; - let reject: (err: AFCError) => void; - const promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - promises.push(promise); + let _resolve: (val?: any) => void + let _reject: (err: AFCError) => void + const promise = new Promise((resolve, reject) => { + _resolve = resolve + _reject = reject + }) + promises.push(promise) // wrap upload in a function in case we need to save it for later const uploadFile = (tries = 0) => { - numOpenFiles++; + numOpenFiles++ _this .uploadFile(filePath, remotePath) .then(() => { - resolve(); - numOpenFiles--; - const fn = pendingFileUploads.pop(); - if (fn) { - fn(); - } + _resolve() + numOpenFiles-- + const fn = pendingFileUploads.pop() + if (fn) + fn() }) .catch((err: AFCError) => { // Couldn't get fd for whatever reason, try again @@ -167,33 +168,35 @@ export class AFCClient extends ServiceClient { if (err.status === AFC_STATUS.NO_RESOURCES && tries < 10) { debug( `Received NO_RESOURCES from AFC, retrying ${filePath} upload. ${tries}`, - ); - uploadFile(tries++); - } else { - numOpenFiles--; - reject(err); + ) + uploadFile(tries++) } - }); - }; + else { + numOpenFiles-- + _reject(err) + } + }) + } if (numOpenFiles < MAX_OPEN_FILES) { - uploadFile(); - } else { + uploadFile() + } + else { debug( `numOpenFiles >= ${MAX_OPEN_FILES}, adding to pending queue. Length: ${pendingFileUploads.length}`, - ); - pendingFileUploads.push(uploadFile); + ) + pendingFileUploads.push(uploadFile) } } } - await Promise.all(promises); + await Promise.all(promises) } } } function toCString(s: string) { - const buf = Buffer.alloc(s.length + 1); - const len = buf.write(s); - buf.writeUInt8(0, len); - return buf; + const buf = Buffer.alloc(s.length + 1) + const len = buf.write(s) + buf.writeUInt8(0, len) + return buf } diff --git a/src/ios/lib/client/client.ts b/src/ios/lib/client/client.ts index c1af738..ba3c2e8 100644 --- a/src/ios/lib/client/client.ts +++ b/src/ios/lib/client/client.ts @@ -1,6 +1,6 @@ -import type * as net from 'net'; +import type * as net from 'node:net' -import type { ProtocolClient } from '../protocol'; +import type { ProtocolClient } from '../protocol' export abstract class ServiceClient { constructor(public socket: net.Socket, protected protocolClient: T) {} @@ -8,6 +8,6 @@ export abstract class ServiceClient { export class ResponseError extends Error { constructor(msg: string, public response: any) { - super(msg); + super(msg) } } diff --git a/src/ios/lib/client/debugserver.ts b/src/ios/lib/client/debugserver.ts index aca65d9..8f1c5d5 100644 --- a/src/ios/lib/client/debugserver.ts +++ b/src/ios/lib/client/debugserver.ts @@ -1,78 +1,78 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; -import * as path from 'path'; +import type * as net from 'node:net' +import * as path from 'node:path' +import Debug from 'debug' -import { GDBProtocolClient } from '../protocol/gdb'; +import { GDBProtocolClient } from '../protocol/gdb' -import { ServiceClient } from './client'; +import { ServiceClient } from './client' -const debug = Debug('native-run:ios:lib:client:debugserver'); +const debug = Debug('native-run:ios:lib:client:debugserver') export class DebugserverClient extends ServiceClient { constructor(public socket: net.Socket) { - super(socket, new GDBProtocolClient(socket)); + super(socket, new GDBProtocolClient(socket)) } async setMaxPacketSize(size: number) { - return this.sendCommand('QSetMaxPacketSize:', [size.toString()]); + return this.sendCommand('QSetMaxPacketSize:', [size.toString()]) } async setWorkingDir(workingDir: string) { - return this.sendCommand('QSetWorkingDir:', [workingDir]); + return this.sendCommand('QSetWorkingDir:', [workingDir]) } async checkLaunchSuccess() { - return this.sendCommand('qLaunchSuccess', []); + return this.sendCommand('qLaunchSuccess', []) } async attachByName(name: string) { - const hexName = Buffer.from(name).toString('hex'); - return this.sendCommand(`vAttachName;${hexName}`, []); + const hexName = Buffer.from(name).toString('hex') + return this.sendCommand(`vAttachName;${hexName}`, []) } async continue() { - return this.sendCommand('c', []); + return this.sendCommand('c', []) } halt() { // ^C - debug('Sending ^C to debugserver'); - return this.protocolClient.socket.write('\u0003'); + debug('Sending ^C to debugserver') + return this.protocolClient.socket.write('\u0003') } async kill() { - const msg: any = { cmd: 'k', args: [] }; + const msg: any = { cmd: 'k', args: [] } return this.protocolClient.sendMessage( msg, (resp: string, resolve: any, reject: any) => { - this.protocolClient.socket.write('+'); - const parts = resp.split(';'); + this.protocolClient.socket.write('+') + const parts = resp.split(';') for (const part of parts) { if (part.includes('description')) { // description:{hex encoded message like: "Terminated with signal 9"} - resolve(Buffer.from(part.split(':')[1], 'hex').toString('ascii')); + resolve(Buffer.from(part.split(':')[1], 'hex').toString('ascii')) } } }, - ); + ) } // TODO support app args // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets // A arglen,argnum,arg, async launchApp(appPath: string, executableName: string) { - const fullPath = path.join(appPath, executableName); - const hexAppPath = Buffer.from(fullPath).toString('hex'); - const appCommand = `A${hexAppPath.length},0,${hexAppPath}`; - return this.sendCommand(appCommand, []); + const fullPath = path.join(appPath, executableName) + const hexAppPath = Buffer.from(fullPath).toString('hex') + const appCommand = `A${hexAppPath.length},0,${hexAppPath}` + return this.sendCommand(appCommand, []) } async sendCommand(cmd: string, args: string[]) { - const msg = { cmd, args }; - debug(`Sending command: ${cmd}, args: ${args}`); - const resp = await this.protocolClient.sendMessage(msg); + const msg = { cmd, args } + debug(`Sending command: ${cmd}, args: ${args}`) + const resp = await this.protocolClient.sendMessage(msg) // we need to ACK as well - this.protocolClient.socket.write('+'); - return resp; + this.protocolClient.socket.write('+') + return resp } } diff --git a/src/ios/lib/client/index.ts b/src/ios/lib/client/index.ts index 79840e5..fb192d5 100644 --- a/src/ios/lib/client/index.ts +++ b/src/ios/lib/client/index.ts @@ -1,7 +1,7 @@ -export * from './client'; -export * from './afc'; -export * from './debugserver'; -export * from './installation_proxy'; -export * from './lockdownd'; -export * from './mobile_image_mounter'; -export * from './usbmuxd'; +export * from './client' +export * from './afc' +export * from './debugserver' +export * from './installation_proxy' +export * from './lockdownd' +export * from './mobile_image_mounter' +export * from './usbmuxd' diff --git a/src/ios/lib/client/installation_proxy.ts b/src/ios/lib/client/installation_proxy.ts index 6793a5d..cc38f39 100644 --- a/src/ios/lib/client/installation_proxy.ts +++ b/src/ios/lib/client/installation_proxy.ts @@ -1,36 +1,36 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; +import type * as net from 'node:net' +import Debug from 'debug' -import type { LockdownCommand, LockdownResponse } from '../protocol/lockdown'; -import { LockdownProtocolClient } from '../protocol/lockdown'; +import type { LockdownCommand, LockdownResponse } from '../protocol/lockdown' +import { LockdownProtocolClient } from '../protocol/lockdown' -import { ResponseError, ServiceClient } from './client'; +import { ResponseError, ServiceClient } from './client' -const debug = Debug('native-run:ios:lib:client:installation_proxy'); +const debug = Debug('native-run:ios:lib:client:installation_proxy') interface IPOptions { - ApplicationsType?: 'Any'; - PackageType?: 'Developer'; - CFBundleIdentifier?: string; + ApplicationsType?: 'Any' + PackageType?: 'Developer' + CFBundleIdentifier?: string ReturnAttributes?: ( | 'CFBundleIdentifier' | 'CFBundleExecutable' | 'Container' | 'Path' - )[]; - BundleIDs?: string[]; + )[] + BundleIDs?: string[] } interface IPInstallPercentCompleteResponseItem extends LockdownResponse { - PercentComplete: number; + PercentComplete: number } interface IPInstallCFBundleIdentifierResponseItem { - CFBundleIdentifier: string; + CFBundleIdentifier: string } interface IPInstallCompleteResponseItem extends LockdownResponse { - Status: 'Complete'; + Status: 'Complete' } /* * [{ "PercentComplete": 5, "Status": "CreatingStagingDirectory" }] @@ -39,18 +39,18 @@ interface IPInstallCompleteResponseItem extends LockdownResponse { * [{ "CFBundleIdentifier": "my.company.app" }] * [{ "Status": "Complete" }] */ -type IPInstallPercentCompleteResponse = IPInstallPercentCompleteResponseItem[]; +type IPInstallPercentCompleteResponse = IPInstallPercentCompleteResponseItem[] type IPInstallCFBundleIdentifierResponse = - IPInstallCFBundleIdentifierResponseItem[]; -type IPInstallCompleteResponse = IPInstallCompleteResponseItem[]; + IPInstallCFBundleIdentifierResponseItem[] +type IPInstallCompleteResponse = IPInstallCompleteResponseItem[] interface IPMessage extends LockdownCommand { - Command: string; - ClientOptions: IPOptions; + Command: string + ClientOptions: IPOptions } interface IPLookupResponseItem extends LockdownResponse { - LookupResult: IPLookupResult; + LookupResult: IPLookupResult } /* * [{ @@ -58,45 +58,45 @@ interface IPLookupResponseItem extends LockdownResponse { * Status: "Complete" * }] */ -type IPLookupResponse = IPLookupResponseItem[]; +type IPLookupResponse = IPLookupResponseItem[] export interface IPLookupResult { // BundleId [key: string]: { - Container: string; - CFBundleIdentifier: string; - CFBundleExecutable: string; - Path: string; - }; + Container: string + CFBundleIdentifier: string + CFBundleExecutable: string + Path: string + } } function isIPLookupResponse(resp: any): resp is IPLookupResponse { - return resp.length && resp[0].LookupResult !== undefined; + return resp.length && resp[0].LookupResult !== undefined } function isIPInstallPercentCompleteResponse( resp: any, ): resp is IPInstallPercentCompleteResponse { - return resp.length && resp[0].PercentComplete !== undefined; + return resp.length && resp[0].PercentComplete !== undefined } function isIPInstallCFBundleIdentifierResponse( resp: any, ): resp is IPInstallCFBundleIdentifierResponse { - return resp.length && resp[0].CFBundleIdentifier !== undefined; + return resp.length && resp[0].CFBundleIdentifier !== undefined } function isIPInstallCompleteResponse( resp: any, ): resp is IPInstallCompleteResponse { - return resp.length && resp[0].Status === 'Complete'; + return resp.length && resp[0].Status === 'Complete' } export class InstallationProxyClient extends ServiceClient< LockdownProtocolClient > { constructor(public socket: net.Socket) { - super(socket, new LockdownProtocolClient(socket)); + super(socket, new LockdownProtocolClient(socket)) } async lookupApp( @@ -111,7 +111,7 @@ export class InstallationProxyClient extends ServiceClient< ApplicationsType: 'Any', }, ) { - debug(`lookupApp, options: ${JSON.stringify(options)}`); + debug(`lookupApp, options: ${JSON.stringify(options)}`) const resp = await this.protocolClient.sendMessage({ Command: 'Lookup', @@ -119,12 +119,11 @@ export class InstallationProxyClient extends ServiceClient< BundleIDs: bundleIds, ...options, }, - }); - if (isIPLookupResponse(resp)) { - return resp[0].LookupResult; - } else { - throw new ResponseError(`There was an error looking up app`, resp); - } + }) + if (isIPLookupResponse(resp)) + return resp[0].LookupResult + else + throw new ResponseError('There was an error looking up app', resp) } async installApp( @@ -135,7 +134,7 @@ export class InstallationProxyClient extends ServiceClient< PackageType: 'Developer', }, ) { - debug(`installApp, packagePath: ${packagePath}, bundleId: ${bundleId}`); + debug(`installApp, packagePath: ${packagePath}, bundleId: ${bundleId}`) return this.protocolClient.sendMessage( { @@ -148,17 +147,20 @@ export class InstallationProxyClient extends ServiceClient< }, (resp: any, resolve, reject) => { if (isIPInstallCompleteResponse(resp)) { - resolve(); - } else if (isIPInstallPercentCompleteResponse(resp)) { + resolve() + } + else if (isIPInstallPercentCompleteResponse(resp)) { debug( `Installation status: ${resp[0].Status}, %${resp[0].PercentComplete}`, - ); - } else if (isIPInstallCFBundleIdentifierResponse(resp)) { - debug(`Installed app: ${resp[0].CFBundleIdentifier}`); - } else { - reject(new ResponseError('There was an error installing app', resp)); + ) + } + else if (isIPInstallCFBundleIdentifierResponse(resp)) { + debug(`Installed app: ${resp[0].CFBundleIdentifier}`) + } + else { + reject(new ResponseError('There was an error installing app', resp)) } }, - ); + ) } } diff --git a/src/ios/lib/client/lockdownd.ts b/src/ios/lib/client/lockdownd.ts index e1d36c0..c8c7335 100644 --- a/src/ios/lib/client/lockdownd.ts +++ b/src/ios/lib/client/lockdownd.ts @@ -1,137 +1,136 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; -import * as tls from 'tls'; +import type * as net from 'node:net' +import * as tls from 'node:tls' +import Debug from 'debug' -import { LockdownProtocolClient } from '../protocol/lockdown'; +import { LockdownProtocolClient } from '../protocol/lockdown' -import { ResponseError, ServiceClient } from './client'; -import type { UsbmuxdPairRecord } from './usbmuxd'; +import { ResponseError, ServiceClient } from './client' +import type { UsbmuxdPairRecord } from './usbmuxd' -const debug = Debug('native-run:ios:lib:client:lockdownd'); +const debug = Debug('native-run:ios:lib:client:lockdownd') export interface DeviceValues { - BasebandCertId: number; + BasebandCertId: number BasebandKeyHashInformation: { - AKeyStatus: number; - SKeyHash: Buffer; - SKeyStatus: number; - }; - BasebandSerialNumber: Buffer; - BasebandVersion: string; - BoardId: number; - BuildVersion: string; - ChipID: number; - DeviceClass: string; - DeviceColor: string; - DeviceName: string; - DieID: number; - HardwareModel: string; - HasSiDP: boolean; - PartitionType: string; - ProductName: string; - ProductType: string; - ProductVersion: string; - ProductionSOC: boolean; - ProtocolVersion: string; - TelephonyCapability: boolean; - UniqueChipID: number; - UniqueDeviceID: string; - WiFiAddress: string; - [key: string]: any; + AKeyStatus: number + SKeyHash: Buffer + SKeyStatus: number + } + BasebandSerialNumber: Buffer + BasebandVersion: string + BoardId: number + BuildVersion: string + ChipID: number + DeviceClass: string + DeviceColor: string + DeviceName: string + DieID: number + HardwareModel: string + HasSiDP: boolean + PartitionType: string + ProductName: string + ProductType: string + ProductVersion: string + ProductionSOC: boolean + ProtocolVersion: string + TelephonyCapability: boolean + UniqueChipID: number + UniqueDeviceID: string + WiFiAddress: string + [key: string]: any } interface LockdowndServiceResponse { - Request: 'StartService'; - Service: string; - Port: number; - EnableServiceSSL?: boolean; // Only on iOS 13+ + Request: 'StartService' + Service: string + Port: number + EnableServiceSSL?: boolean // Only on iOS 13+ } interface LockdowndSessionResponse { - Request: 'StartSession'; - EnableSessionSSL: boolean; + Request: 'StartSession' + EnableSessionSSL: boolean } interface LockdowndAllValuesResponse { - Request: 'GetValue'; - Value: DeviceValues; + Request: 'GetValue' + Value: DeviceValues } interface LockdowndValueResponse { - Request: 'GetValue'; - Key: string; - Value: string; + Request: 'GetValue' + Key: string + Value: string } interface LockdowndQueryTypeResponse { - Request: 'QueryType'; - Type: string; + Request: 'QueryType' + Type: string } function isLockdowndServiceResponse( resp: any, ): resp is LockdowndServiceResponse { return ( - resp.Request === 'StartService' && - resp.Service !== undefined && - resp.Port !== undefined - ); + resp.Request === 'StartService' + && resp.Service !== undefined + && resp.Port !== undefined + ) } function isLockdowndSessionResponse( resp: any, ): resp is LockdowndSessionResponse { - return resp.Request === 'StartSession'; + return resp.Request === 'StartSession' } function isLockdowndAllValuesResponse( resp: any, ): resp is LockdowndAllValuesResponse { - return resp.Request === 'GetValue' && resp.Value !== undefined; + return resp.Request === 'GetValue' && resp.Value !== undefined } function isLockdowndValueResponse(resp: any): resp is LockdowndValueResponse { return ( - resp.Request === 'GetValue' && - resp.Key !== undefined && - typeof resp.Value === 'string' - ); + resp.Request === 'GetValue' + && resp.Key !== undefined + && typeof resp.Value === 'string' + ) } function isLockdowndQueryTypeResponse( resp: any, ): resp is LockdowndQueryTypeResponse { - return resp.Request === 'QueryType' && resp.Type !== undefined; + return resp.Request === 'QueryType' && resp.Type !== undefined } export class LockdowndClient extends ServiceClient { constructor(public socket: net.Socket) { - super(socket, new LockdownProtocolClient(socket)); + super(socket, new LockdownProtocolClient(socket)) } async startService(name: string) { - debug(`startService: ${name}`); + debug(`startService: ${name}`) const resp = await this.protocolClient.sendMessage({ Request: 'StartService', Service: name, - }); + }) - if (isLockdowndServiceResponse(resp)) { - return { port: resp.Port, enableServiceSSL: !!resp.EnableServiceSSL }; - } else { - throw new ResponseError(`Error starting service ${name}`, resp); - } + if (isLockdowndServiceResponse(resp)) + return { port: resp.Port, enableServiceSSL: !!resp.EnableServiceSSL } + else + throw new ResponseError(`Error starting service ${name}`, resp) } async startSession(pairRecord: UsbmuxdPairRecord) { - debug(`startSession: ${pairRecord}`); + debug(`startSession: ${pairRecord}`) const resp = await this.protocolClient.sendMessage({ Request: 'StartSession', HostID: pairRecord.HostID, SystemBUID: pairRecord.SystemBUID, - }); + }) if (isLockdowndSessionResponse(resp)) { if (resp.EnableSessionSSL) { @@ -144,64 +143,62 @@ export class LockdowndClient extends ServiceClient { key: pairRecord.RootPrivateKey, }), }, - ); - debug(`Socket upgraded to TLS connection`); + ) + debug('Socket upgraded to TLS connection') } // TODO: save sessionID for StopSession? - } else { - throw new ResponseError('Error starting session', resp); + } + else { + throw new ResponseError('Error starting session', resp) } } async getAllValues() { - debug(`getAllValues`); + debug('getAllValues') - const resp = await this.protocolClient.sendMessage({ Request: 'GetValue' }); + const resp = await this.protocolClient.sendMessage({ Request: 'GetValue' }) - if (isLockdowndAllValuesResponse(resp)) { - return resp.Value; - } else { - throw new ResponseError('Error getting lockdown value', resp); - } + if (isLockdowndAllValuesResponse(resp)) + return resp.Value + else + throw new ResponseError('Error getting lockdown value', resp) } async getValue(val: string) { - debug(`getValue: ${val}`); + debug(`getValue: ${val}`) const resp = await this.protocolClient.sendMessage({ Request: 'GetValue', Key: val, - }); + }) - if (isLockdowndValueResponse(resp)) { - return resp.Value; - } else { - throw new ResponseError('Error getting lockdown value', resp); - } + if (isLockdowndValueResponse(resp)) + return resp.Value + else + throw new ResponseError('Error getting lockdown value', resp) } async queryType() { - debug('queryType'); + debug('queryType') const resp = await this.protocolClient.sendMessage({ Request: 'QueryType', - }); + }) - if (isLockdowndQueryTypeResponse(resp)) { - return resp.Type; - } else { - throw new ResponseError('Error getting lockdown query type', resp); - } + if (isLockdowndQueryTypeResponse(resp)) + return resp.Type + else + throw new ResponseError('Error getting lockdown query type', resp) } async doHandshake(pairRecord: UsbmuxdPairRecord) { - debug('doHandshake'); + debug('doHandshake') // if (await this.lockdownQueryType() !== 'com.apple.mobile.lockdown') { // throw new Error('Invalid type received from lockdown handshake'); // } // await this.getLockdownValue('ProductVersion'); // TODO: validate pair and pair - await this.startSession(pairRecord); + await this.startSession(pairRecord) } } diff --git a/src/ios/lib/client/mobile_image_mounter.ts b/src/ios/lib/client/mobile_image_mounter.ts index 4ce1a17..e9abe00 100644 --- a/src/ios/lib/client/mobile_image_mounter.ts +++ b/src/ios/lib/client/mobile_image_mounter.ts @@ -1,76 +1,76 @@ -import * as Debug from 'debug'; -import * as fs from 'fs'; -import type * as net from 'net'; +import * as fs from 'node:fs' +import type * as net from 'node:net' +import Debug from 'debug' -import type { LockdownCommand, LockdownResponse } from '../protocol/lockdown'; +import type { LockdownCommand, LockdownResponse } from '../protocol/lockdown' import { LockdownProtocolClient, isLockdownResponse, -} from '../protocol/lockdown'; +} from '../protocol/lockdown' -import { ResponseError, ServiceClient } from './client'; +import { ResponseError, ServiceClient } from './client' -const debug = Debug('native-run:ios:lib:client:mobile_image_mounter'); +const debug = Debug('native-run:ios:lib:client:mobile_image_mounter') -export type MIMMountResponse = LockdownResponse; +export type MIMMountResponse = LockdownResponse export interface MIMMessage extends LockdownCommand { - ImageType: string; + ImageType: string } export interface MIMLookupResponse extends LockdownResponse { - ImageSignature?: string; + ImageSignature?: string } export interface MIMUploadCompleteResponse extends LockdownResponse { - Status: 'Complete'; + Status: 'Complete' } export interface MIMUploadReceiveBytesResponse extends LockdownResponse { - Status: 'ReceiveBytesAck'; + Status: 'ReceiveBytesAck' } function isMIMUploadCompleteResponse( resp: any, ): resp is MIMUploadCompleteResponse { - return resp.Status === 'Complete'; + return resp.Status === 'Complete' } function isMIMUploadReceiveBytesResponse( resp: any, ): resp is MIMUploadReceiveBytesResponse { - return resp.Status === 'ReceiveBytesAck'; + return resp.Status === 'ReceiveBytesAck' } export class MobileImageMounterClient extends ServiceClient< LockdownProtocolClient > { constructor(socket: net.Socket) { - super(socket, new LockdownProtocolClient(socket)); + super(socket, new LockdownProtocolClient(socket)) } async mountImage(imagePath: string, imageSig: Buffer) { - debug(`mountImage: ${imagePath}`); + debug(`mountImage: ${imagePath}`) const resp = await this.protocolClient.sendMessage({ Command: 'MountImage', ImagePath: imagePath, ImageSignature: imageSig, ImageType: 'Developer', - }); + }) if (!isLockdownResponse(resp) || resp.Status !== 'Complete') { throw new ResponseError( `There was an error mounting ${imagePath} on device`, resp, - ); + ) } } async uploadImage(imagePath: string, imageSig: Buffer) { - debug(`uploadImage: ${imagePath}`); + debug(`uploadImage: ${imagePath}`) - const imageSize = fs.statSync(imagePath).size; + const imageSize = fs.statSync(imagePath).size return this.protocolClient.sendMessage( { Command: 'ReceiveBytes', @@ -80,29 +80,31 @@ export class MobileImageMounterClient extends ServiceClient< }, (resp: any, resolve, reject) => { if (isMIMUploadReceiveBytesResponse(resp)) { - const imageStream = fs.createReadStream(imagePath); - imageStream.pipe(this.protocolClient.socket, { end: false }); - imageStream.on('error', err => reject(err)); - } else if (isMIMUploadCompleteResponse(resp)) { - resolve(); - } else { + const imageStream = fs.createReadStream(imagePath) + imageStream.pipe(this.protocolClient.socket, { end: false }) + imageStream.on('error', err => reject(err)) + } + else if (isMIMUploadCompleteResponse(resp)) { + resolve() + } + else { reject( new ResponseError( `There was an error uploading image ${imagePath} to the device`, resp, ), - ); + ) } }, - ); + ) } async lookupImage() { - debug('lookupImage'); + debug('lookupImage') return this.protocolClient.sendMessage({ Command: 'LookupImage', ImageType: 'Developer', - }); + }) } } diff --git a/src/ios/lib/client/usbmuxd.ts b/src/ios/lib/client/usbmuxd.ts index 8161e29..02e372c 100644 --- a/src/ios/lib/client/usbmuxd.ts +++ b/src/ios/lib/client/usbmuxd.ts @@ -1,83 +1,82 @@ -import * as Debug from 'debug'; -import * as net from 'net'; -import * as plist from 'plist'; +import * as net from 'node:net' +import Debug from 'debug' +import * as plist from 'plist' -import { UsbmuxProtocolClient } from '../protocol/usbmux'; +import { UsbmuxProtocolClient } from '../protocol/usbmux' -import { ResponseError, ServiceClient } from './client'; +import { ResponseError, ServiceClient } from './client' -const debug = Debug('native-run:ios:lib:client:usbmuxd'); +const debug = Debug('native-run:ios:lib:client:usbmuxd') export interface UsbmuxdDeviceProperties { - ConnectionSpeed: number; - ConnectionType: 'USB'; - DeviceID: number; - LocationID: number; - ProductID: number; - SerialNumber: string; + ConnectionSpeed: number + ConnectionType: 'USB' + DeviceID: number + LocationID: number + ProductID: number + SerialNumber: string } export interface UsbmuxdDevice { - DeviceID: number; - MessageType: 'Attached'; // TODO: what else? - Properties: UsbmuxdDeviceProperties; + DeviceID: number + MessageType: 'Attached' // TODO: what else? + Properties: UsbmuxdDeviceProperties } export interface UsbmuxdConnectResponse { - MessageType: 'Result'; - Number: number; + MessageType: 'Result' + Number: number } export interface UsbmuxdDeviceResponse { - DeviceList: UsbmuxdDevice[]; + DeviceList: UsbmuxdDevice[] } export interface UsbmuxdPairRecordResponse { - PairRecordData: Buffer; + PairRecordData: Buffer } export interface UsbmuxdPairRecord { - DeviceCertificate: Buffer; - EscrowBag: Buffer; - HostCertificate: Buffer; - HostID: string; - HostPrivateKey: Buffer; - RootCertificate: Buffer; - RootPrivateKey: Buffer; - SystemBUID: string; - WiFiMACAddress: string; + DeviceCertificate: Buffer + EscrowBag: Buffer + HostCertificate: Buffer + HostID: string + HostPrivateKey: Buffer + RootCertificate: Buffer + RootPrivateKey: Buffer + SystemBUID: string + WiFiMACAddress: string } function isUsbmuxdConnectResponse(resp: any): resp is UsbmuxdConnectResponse { - return resp.MessageType === 'Result' && resp.Number !== undefined; + return resp.MessageType === 'Result' && resp.Number !== undefined } function isUsbmuxdDeviceResponse(resp: any): resp is UsbmuxdDeviceResponse { - return resp.DeviceList !== undefined; + return resp.DeviceList !== undefined } function isUsbmuxdPairRecordResponse( resp: any, ): resp is UsbmuxdPairRecordResponse { - return resp.PairRecordData !== undefined; + return resp.PairRecordData !== undefined } export class UsbmuxdClient extends ServiceClient { constructor(public socket: net.Socket) { - super(socket, new UsbmuxProtocolClient(socket)); + super(socket, new UsbmuxProtocolClient(socket)) } static connectUsbmuxdSocket() { - debug('connectUsbmuxdSocket'); - if ('win32' === process.platform) { - return net.connect({ port: 27015, host: 'localhost' }); - } else { - return net.connect({ path: '/var/run/usbmuxd' }); - } + debug('connectUsbmuxdSocket') + if (process.platform === 'win32') + return net.connect({ port: 27015, host: 'localhost' }) + else + return net.connect({ path: '/var/run/usbmuxd' }) } async connect(device: UsbmuxdDevice, port: number) { - debug(`connect: ${device.DeviceID} on port ${port}`); + debug(`connect: ${device.DeviceID} on port ${port}`) const resp = await this.protocolClient.sendMessage({ messageType: 'Connect', @@ -85,80 +84,79 @@ export class UsbmuxdClient extends ServiceClient { DeviceID: device.DeviceID, PortNumber: htons(port), }, - }); + }) if (isUsbmuxdConnectResponse(resp) && resp.Number === 0) { - return this.protocolClient.socket; - } else { + return this.protocolClient.socket + } + else { throw new ResponseError( `There was an error connecting to ${device.DeviceID} on port ${port}`, resp, - ); + ) } } async getDevices() { - debug('getDevices'); + debug('getDevices') const resp = await this.protocolClient.sendMessage({ messageType: 'ListDevices', - }); + }) - if (isUsbmuxdDeviceResponse(resp)) { - return resp.DeviceList; - } else { - throw new ResponseError('Invalid response from getDevices', resp); - } + if (isUsbmuxdDeviceResponse(resp)) + return resp.DeviceList + else + throw new ResponseError('Invalid response from getDevices', resp) } async getDevice(udid?: string) { - debug(`getDevice ${udid ? 'udid: ' + udid : ''}`); - const devices = await this.getDevices(); + debug(`getDevice ${udid ? `udid: ${udid}` : ''}`) + const devices = await this.getDevices() - if (!devices.length) { - throw new Error('No devices found'); - } + if (!devices.length) + throw new Error('No devices found') - if (!udid) { - return devices[0]; - } + if (!udid) + return devices[0] for (const device of devices) { - if (device.Properties && device.Properties.SerialNumber === udid) { - return device; - } + if (device.Properties && device.Properties.SerialNumber === udid) + return device } - throw new Error(`No device with udid ${udid} found`); + throw new Error(`No device with udid ${udid} found`) } async readPairRecord(udid: string): Promise { - debug(`readPairRecord: ${udid}`); + debug(`readPairRecord: ${udid}`) const resp = await this.protocolClient.sendMessage({ messageType: 'ReadPairRecord', extraFields: { PairRecordID: udid }, - }); + }) if (isUsbmuxdPairRecordResponse(resp)) { // the pair record can be created as a binary plist - const BPLIST_MAGIC = Buffer.from('bplist00'); + const BPLIST_MAGIC = Buffer.from('bplist00') if (BPLIST_MAGIC.compare(resp.PairRecordData, 0, 8) === 0) { - debug('Binary plist pair record detected.'); - const bplistParser = await import('bplist-parser'); - return bplistParser.parseBuffer(resp.PairRecordData)[0]; - } else { - return plist.parse(resp.PairRecordData.toString()) as any; // TODO: type guard + debug('Binary plist pair record detected.') + const bplistParser = await import('bplist-parser') + return bplistParser.parseBuffer(resp.PairRecordData)[0] } - } else { + else { + return plist.parse(resp.PairRecordData.toString()) as any // TODO: type guard + } + } + else { throw new ResponseError( `There was an error reading pair record for udid: ${udid}`, resp, - ); + ) } } } function htons(n: number) { - return ((n & 0xff) << 8) | ((n >> 8) & 0xff); + return ((n & 0xFF) << 8) | ((n >> 8) & 0xFF) } diff --git a/src/ios/lib/index.ts b/src/ios/lib/index.ts index 72ab848..b7f3fa5 100644 --- a/src/ios/lib/index.ts +++ b/src/ios/lib/index.ts @@ -1,3 +1,3 @@ -export * from './client'; -export * from './protocol'; -export * from './manager'; +export * from './client' +export * from './protocol' +export * from './manager' diff --git a/src/ios/lib/lib-errors.ts b/src/ios/lib/lib-errors.ts index 2de4aa9..300a629 100644 --- a/src/ios/lib/lib-errors.ts +++ b/src/ios/lib/lib-errors.ts @@ -1,10 +1,10 @@ /** * Type union of error codes we get back from the protocol. */ -export type IOSLibErrorCode = 'DeviceLocked'; +export type IOSLibErrorCode = 'DeviceLocked' export class IOSLibError extends Error implements NodeJS.ErrnoException { constructor(message: string, readonly code: IOSLibErrorCode) { - super(message); + super(message) } } diff --git a/src/ios/lib/manager.ts b/src/ios/lib/manager.ts index 2c475cf..29275b0 100644 --- a/src/ios/lib/manager.ts +++ b/src/ios/lib/manager.ts @@ -1,80 +1,80 @@ -import type * as net from 'net'; -import { Duplex } from 'stream'; -import * as tls from 'tls'; - -import type { ServiceClient } from './client'; -import { AFCClient } from './client/afc'; -import { DebugserverClient } from './client/debugserver'; -import { InstallationProxyClient } from './client/installation_proxy'; -import { LockdowndClient } from './client/lockdownd'; -import { MobileImageMounterClient } from './client/mobile_image_mounter'; -import type { UsbmuxdDevice, UsbmuxdPairRecord } from './client/usbmuxd'; -import { UsbmuxdClient } from './client/usbmuxd'; +import type * as net from 'node:net' +import { Duplex } from 'node:stream' +import * as tls from 'node:tls' + +import type { ServiceClient } from './client' +import { AFCClient } from './client/afc' +import { DebugserverClient } from './client/debugserver' +import { InstallationProxyClient } from './client/installation_proxy' +import { LockdowndClient } from './client/lockdownd' +import { MobileImageMounterClient } from './client/mobile_image_mounter' +import type { UsbmuxdDevice, UsbmuxdPairRecord } from './client/usbmuxd' +import { UsbmuxdClient } from './client/usbmuxd' export class ClientManager { - private connections: net.Socket[]; + private connections: net.Socket[] constructor( public pairRecord: UsbmuxdPairRecord, public device: UsbmuxdDevice, private lockdowndClient: LockdowndClient, ) { - this.connections = [lockdowndClient.socket]; + this.connections = [lockdowndClient.socket] } static async create(udid?: string) { const usbmuxClient = new UsbmuxdClient( UsbmuxdClient.connectUsbmuxdSocket(), - ); - const device = await usbmuxClient.getDevice(udid); + ) + const device = await usbmuxClient.getDevice(udid) const pairRecord = await usbmuxClient.readPairRecord( device.Properties.SerialNumber, - ); - const lockdownSocket = await usbmuxClient.connect(device, 62078); - const lockdownClient = new LockdowndClient(lockdownSocket); - await lockdownClient.doHandshake(pairRecord); - return new ClientManager(pairRecord, device, lockdownClient); + ) + const lockdownSocket = await usbmuxClient.connect(device, 62078) + const lockdownClient = new LockdowndClient(lockdownSocket) + await lockdownClient.doHandshake(pairRecord) + return new ClientManager(pairRecord, device, lockdownClient) } async getUsbmuxdClient() { const usbmuxClient = new UsbmuxdClient( UsbmuxdClient.connectUsbmuxdSocket(), - ); - this.connections.push(usbmuxClient.socket); - return usbmuxClient; + ) + this.connections.push(usbmuxClient.socket) + return usbmuxClient } async getLockdowndClient() { const usbmuxClient = new UsbmuxdClient( UsbmuxdClient.connectUsbmuxdSocket(), - ); - const lockdownSocket = await usbmuxClient.connect(this.device, 62078); - const lockdownClient = new LockdowndClient(lockdownSocket); - this.connections.push(lockdownClient.socket); - return lockdownClient; + ) + const lockdownSocket = await usbmuxClient.connect(this.device, 62078) + const lockdownClient = new LockdowndClient(lockdownSocket) + this.connections.push(lockdownClient.socket) + return lockdownClient } async getLockdowndClientWithHandshake() { - const lockdownClient = await this.getLockdowndClient(); - await lockdownClient.doHandshake(this.pairRecord); - return lockdownClient; + const lockdownClient = await this.getLockdowndClient() + await lockdownClient.doHandshake(this.pairRecord) + return lockdownClient } async getAFCClient() { - return this.getServiceClient('com.apple.afc', AFCClient); + return this.getServiceClient('com.apple.afc', AFCClient) } async getInstallationProxyClient() { return this.getServiceClient( 'com.apple.mobile.installation_proxy', InstallationProxyClient, - ); + ) } async getMobileImageMounterClient() { return this.getServiceClient( 'com.apple.mobile.mobile_image_mounter', MobileImageMounterClient, - ); + ) } async getDebugserverClient() { @@ -83,14 +83,15 @@ export class ClientManager { return await this.getServiceClient( 'com.apple.debugserver.DVTSecureSocketProxy', DebugserverClient, - ); - } catch { + ) + } + catch { // otherwise, fall back to the previous implementation return this.getServiceClient( 'com.apple.debugserver', DebugserverClient, true, - ); + ) } } @@ -99,12 +100,12 @@ export class ClientManager { ServiceType: new (...args: any[]) => T, disableSSL = false, ) { - const { port: servicePort, enableServiceSSL } = - await this.lockdowndClient.startService(name); + const { port: servicePort, enableServiceSSL } + = await this.lockdowndClient.startService(name) const usbmuxClient = new UsbmuxdClient( UsbmuxdClient.connectUsbmuxdSocket(), - ); - let usbmuxdSocket = await usbmuxClient.connect(this.device, servicePort); + ) + let usbmuxdSocket = await usbmuxClient.connect(this.device, servicePort) if (enableServiceSSL) { const tlsOptions: tls.ConnectionOptions = { @@ -114,7 +115,7 @@ export class ClientManager { cert: this.pairRecord.RootCertificate, key: this.pairRecord.RootPrivateKey, }), - }; + } // Some services seem to not support TLS/SSL after the initial handshake // More info: https://github.com/libimobiledevice/libimobiledevice/issues/793 @@ -122,37 +123,39 @@ export class ClientManager { // According to https://nodejs.org/api/tls.html#tls_tls_connect_options_callback we can // pass any Duplex in to tls.connect instead of a Socket. So we'll use our proxy to keep // the TLS wrapper and underlying usbmuxd socket separate. - const proxy: any = new UsbmuxdProxy(usbmuxdSocket); - tlsOptions.socket = proxy; + const proxy: any = new UsbmuxdProxy(usbmuxdSocket) + tlsOptions.socket = proxy - await new Promise((res, rej) => { + await new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { - rej('The TLS handshake failed to complete after 5s.'); - }, 5000); + resolve('The TLS handshake failed to complete after 5s.') + }, 5000) tls.connect(tlsOptions, function (this: tls.TLSSocket) { - clearTimeout(timeoutId); + clearTimeout(timeoutId) // After the handshake, we don't need TLS or the proxy anymore, // since we'll just pass in the naked usbmuxd socket to the service client - this.destroy(); - res(); - }); - }); - } else { - tlsOptions.socket = usbmuxdSocket; - usbmuxdSocket = tls.connect(tlsOptions); + this.destroy() + reject(new Error('The TLS handshake failed to complete.')) + }) + }) + } + else { + tlsOptions.socket = usbmuxdSocket + usbmuxdSocket = tls.connect(tlsOptions) } } - const client = new ServiceType(usbmuxdSocket); - this.connections.push(client.socket); - return client; + const client = new ServiceType(usbmuxdSocket) + this.connections.push(client.socket) + return client } end() { for (const socket of this.connections) { // may already be closed try { - socket.end(); - } catch (err) { + socket.end() + } + catch (err) { // ignore } } @@ -161,16 +164,16 @@ export class ClientManager { class UsbmuxdProxy extends Duplex { constructor(private usbmuxdSock: net.Socket) { - super(); + super() - this.usbmuxdSock.on('data', data => { - this.push(data); - }); + this.usbmuxdSock.on('data', (data) => { + this.push(data) + }) } _write(chunk: any, encoding: string, callback: (err?: Error) => void) { - this.usbmuxdSock.write(chunk); - callback(); + this.usbmuxdSock.write(chunk) + callback() } _read(size: number) { @@ -179,6 +182,6 @@ class UsbmuxdProxy extends Duplex { } _destroy() { - this.usbmuxdSock.removeAllListeners(); + this.usbmuxdSock.removeAllListeners() } } diff --git a/src/ios/lib/protocol/afc.ts b/src/ios/lib/protocol/afc.ts index ddcc8d4..936136f 100644 --- a/src/ios/lib/protocol/afc.ts +++ b/src/ios/lib/protocol/afc.ts @@ -1,42 +1,42 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; +import type * as net from 'node:net' +import Debug from 'debug' -import type { ProtocolReaderCallback, ProtocolWriter } from './protocol'; +import type { ProtocolReaderCallback, ProtocolWriter } from './protocol' import { ProtocolClient, ProtocolReader, ProtocolReaderFactory, -} from './protocol'; +} from './protocol' -const debug = Debug('native-run:ios:lib:protocol:afc'); +const debug = Debug('native-run:ios:lib:protocol:afc') -export const AFC_MAGIC = 'CFA6LPAA'; -export const AFC_HEADER_SIZE = 40; +export const AFC_MAGIC = 'CFA6LPAA' +export const AFC_HEADER_SIZE = 40 export interface AFCHeader { - magic: typeof AFC_MAGIC; - totalLength: number; - headerLength: number; - requestId: number; - operation: AFC_OPS; + magic: typeof AFC_MAGIC + totalLength: number + headerLength: number + requestId: number + operation: AFC_OPS } export interface AFCMessage { - operation: AFC_OPS; - data?: any; - payload?: any; + operation: AFC_OPS + data?: any + payload?: any } export interface AFCResponse { - operation: AFC_OPS; - id: number; - data: Buffer; + operation: AFC_OPS + id: number + data: Buffer } export interface AFCStatusResponse { - operation: AFC_OPS.STATUS; - id: number; - data: number; + operation: AFC_OPS.STATUS + id: number + data: number } /** @@ -96,32 +96,32 @@ export enum AFC_OPS { /** * GetFileInfo */ - GET_FILE_INFO = 0x0000000a, + GET_FILE_INFO = 0x0000000A, /** * GetDeviceInfo */ - GET_DEVINFO = 0x0000000b, + GET_DEVINFO = 0x0000000B, /** * WriteFileAtomic (tmp file+rename) */ - WRITE_FILE_ATOM = 0x0000000c, + WRITE_FILE_ATOM = 0x0000000C, /** * FileRefOpen */ - FILE_OPEN = 0x0000000d, + FILE_OPEN = 0x0000000D, /** * FileRefOpenResult */ - FILE_OPEN_RES = 0x0000000e, + FILE_OPEN_RES = 0x0000000E, /** * FileRefRead */ - FILE_READ = 0x0000000f, + FILE_READ = 0x0000000F, /** * FileRefWrite @@ -176,32 +176,32 @@ export enum AFC_OPS { /** * SetSocketBlockSize (0x800000) */ - SET_SOCKET_BS = 0x0000001a, + SET_SOCKET_BS = 0x0000001A, /** * FileRefLock */ - FILE_LOCK = 0x0000001b, + FILE_LOCK = 0x0000001B, /** * MakeLink */ - MAKE_LINK = 0x0000001c, + MAKE_LINK = 0x0000001C, /** * GetFileHash */ - GET_FILE_HASH = 0x0000001d, + GET_FILE_HASH = 0x0000001D, /** * SetModTime */ - SET_FILE_MOD_TIME = 0x0000001e, + SET_FILE_MOD_TIME = 0x0000001E, /** * GetFileHashWithRange */ - GET_FILE_HASH_RANGE = 0x0000001f, + GET_FILE_HASH_RANGE = 0x0000001F, // iOS 6+ @@ -322,91 +322,92 @@ export enum AFC_FILE_OPEN_FLAGS { function isAFCResponse(resp: any): resp is AFCResponse { return ( - AFC_OPS[resp.operation] !== undefined && - resp.id !== undefined && - resp.data !== undefined - ); + AFC_OPS[resp.operation] !== undefined + && resp.id !== undefined + && resp.data !== undefined + ) } function isStatusResponse(resp: any): resp is AFCStatusResponse { - return isAFCResponse(resp) && resp.operation === AFC_OPS.STATUS; + return isAFCResponse(resp) && resp.operation === AFC_OPS.STATUS } function isErrorStatusResponse(resp: AFCResponse): boolean { - return isStatusResponse(resp) && resp.data !== AFC_STATUS.SUCCESS; + return isStatusResponse(resp) && resp.data !== AFC_STATUS.SUCCESS } class AFCInternalError extends Error { constructor(msg: string, public requestId: number) { - super(msg); + super(msg) } } export class AFCError extends Error { constructor(msg: string, public status: AFC_STATUS) { - super(msg); + super(msg) } } export class AFCProtocolClient extends ProtocolClient { - private requestId = 0; - private requestCallbacks: { [key: number]: ProtocolReaderCallback } = {}; + private requestId = 0 + private requestCallbacks: { [key: number]: ProtocolReaderCallback } = {} constructor(socket: net.Socket) { super( socket, new ProtocolReaderFactory(AFCProtocolReader), new AFCProtocolWriter(), - ); + ) const reader = this.readerFactory.create((resp, err) => { if (err && err instanceof AFCInternalError) { - this.requestCallbacks[err.requestId](resp, err); - } else if (isErrorStatusResponse(resp)) { + this.requestCallbacks[err.requestId](resp, err) + } + else if (isErrorStatusResponse(resp)) { this.requestCallbacks[resp.id]( resp, new AFCError(AFC_STATUS[resp.data], resp.data), - ); - } else { - this.requestCallbacks[resp.id](resp); + ) + } + else { + this.requestCallbacks[resp.id](resp) } - }); - socket.on('data', reader.onData); + }) + socket.on('data', reader.onData) } sendMessage(msg: AFCMessage): Promise { return new Promise((resolve, reject) => { - const requestId = this.requestId++; + const requestId = this.requestId++ this.requestCallbacks[requestId] = async (resp: any, err?: Error) => { if (err) { - reject(err); - return; - } - if (isAFCResponse(resp)) { - resolve(resp); - } else { - reject(new Error('Malformed AFC response')); + reject(err) + return } - }; - this.writer.write(this.socket, { ...msg, requestId }); - }); + if (isAFCResponse(resp)) + resolve(resp) + else + reject(new Error('Malformed AFC response')) + } + this.writer.write(this.socket, { ...msg, requestId }) + }) } } export class AFCProtocolReader extends ProtocolReader { - private header!: AFCHeader; // TODO: ! -> ? + private header!: AFCHeader // TODO: ! -> ? constructor(callback: ProtocolReaderCallback) { - super(AFC_HEADER_SIZE, callback); + super(AFC_HEADER_SIZE, callback) } parseHeader(data: Buffer) { - const magic = data.slice(0, 8).toString('ascii'); + const magic = data.slice(0, 8).toString('ascii') if (magic !== AFC_MAGIC) { throw new AFCInternalError( `Invalid AFC packet received (magic != ${AFC_MAGIC})`, data.readUInt32LE(24), - ); + ) } // technically these are uint64 this.header = { @@ -415,13 +416,13 @@ export class AFCProtocolReader extends ProtocolReader { headerLength: data.readUInt32LE(16), requestId: data.readUInt32LE(24), operation: data.readUInt32LE(32), - }; - - debug(`parse header: ${JSON.stringify(this.header)}`); - if (this.header.headerLength < AFC_HEADER_SIZE) { - throw new AFCInternalError('Invalid AFC header', this.header.requestId); } - return this.header.totalLength - AFC_HEADER_SIZE; + + debug(`parse header: ${JSON.stringify(this.header)}`) + if (this.header.headerLength < AFC_HEADER_SIZE) + throw new AFCInternalError('Invalid AFC header', this.header.requestId) + + return this.header.totalLength - AFC_HEADER_SIZE } parseBody(data: Buffer): AFCResponse | AFCStatusResponse { @@ -429,63 +430,65 @@ export class AFCProtocolReader extends ProtocolReader { operation: this.header.operation, id: this.header.requestId, data, - }; + } if (isStatusResponse(body)) { - const status = data.readUInt32LE(0); + const status = data.readUInt32LE(0) debug( `${AFC_OPS[this.header.operation]} response: ${AFC_STATUS[status]}`, - ); - body.data = status; - } else if (data.length <= 8) { + ) + body.data = status + } + else if (data.length <= 8) { debug( `${ AFC_OPS[this.header.operation] } response: ${Array.prototype.toString.call(body)}`, - ); - } else { + ) + } + else { debug( `${AFC_OPS[this.header.operation]} response length: ${ data.length } bytes`, - ); + ) } - return body; + return body } } export class AFCProtocolWriter implements ProtocolWriter { write(socket: net.Socket, msg: AFCMessage & { requestId: number }) { - const { data, payload, operation, requestId } = msg; - - const dataLength = data ? data.length : 0; - const payloadLength = payload ? payload.length : 0; - - const header = Buffer.alloc(AFC_HEADER_SIZE); - const magic = Buffer.from(AFC_MAGIC); - magic.copy(header); - header.writeUInt32LE(AFC_HEADER_SIZE + dataLength + payloadLength, 8); - header.writeUInt32LE(AFC_HEADER_SIZE + dataLength, 16); - header.writeUInt32LE(requestId, 24); - header.writeUInt32LE(operation, 32); - socket.write(header); - socket.write(data); + const { data, payload, operation, requestId } = msg + + const dataLength = data ? data.length : 0 + const payloadLength = payload ? payload.length : 0 + + const header = Buffer.alloc(AFC_HEADER_SIZE) + const magic = Buffer.from(AFC_MAGIC) + magic.copy(header) + header.writeUInt32LE(AFC_HEADER_SIZE + dataLength + payloadLength, 8) + header.writeUInt32LE(AFC_HEADER_SIZE + dataLength, 16) + header.writeUInt32LE(requestId, 24) + header.writeUInt32LE(operation, 32) + socket.write(header) + socket.write(data) if (data.length <= 8) { debug( `socket write, header: { requestId: ${requestId}, operation: ${ AFC_OPS[operation] }}, body: ${Array.prototype.toString.call(data)}`, - ); - } else { + ) + } + else { debug( `socket write, header: { requestId: ${requestId}, operation: ${AFC_OPS[operation]}}, body: ${data.length} bytes`, - ); + ) } debug( `socket write, bytes written ${header.length} (header), ${data.length} (body)`, - ); - if (payload) { - socket.write(payload); - } + ) + if (payload) + socket.write(payload) } } diff --git a/src/ios/lib/protocol/gdb.ts b/src/ios/lib/protocol/gdb.ts index dd8d852..4545215 100644 --- a/src/ios/lib/protocol/gdb.ts +++ b/src/ios/lib/protocol/gdb.ts @@ -1,19 +1,19 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; +import type * as net from 'node:net' +import Debug from 'debug' -import type { ProtocolReaderCallback, ProtocolWriter } from './protocol'; +import type { ProtocolReaderCallback, ProtocolWriter } from './protocol' import { ProtocolClient, ProtocolReader, ProtocolReaderFactory, -} from './protocol'; +} from './protocol' -const debug = Debug('native-run:ios:lib:protocol:gdb'); -const ACK_SUCCESS = '+'.charCodeAt(0); +const debug = Debug('native-run:ios:lib:protocol:gdb') +const ACK_SUCCESS = '+'.charCodeAt(0) export interface GDBMessage { - cmd: string; - args: string[]; + cmd: string + args: string[] } export class GDBProtocolClient extends ProtocolClient { @@ -22,13 +22,13 @@ export class GDBProtocolClient extends ProtocolClient { socket, new ProtocolReaderFactory(GDBProtocolReader), new GDBProtocolWriter(), - ); + ) } } export class GDBProtocolReader extends ProtocolReader { constructor(callback: ProtocolReaderCallback) { - super(1 /* "Header" is '+' or '-' */, callback); + super(1 /* "Header" is '+' or '-' */, callback) } onData(data?: Buffer) { @@ -36,95 +36,94 @@ export class GDBProtocolReader extends ProtocolReader { // the parent implementation to determine when a payload is complete try { // if there's data, add it to the existing buffer - this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer; + this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer // do we have enough bytes to proceed - if (this.buffer.length < this.headerSize) { - return; // incomplete header, wait for more - } + if (this.buffer.length < this.headerSize) + return // incomplete header, wait for more // first, check the header if (this.parseHeader(this.buffer) === -1) { // we have a valid header so check the body. GDB packets will always be a leading '$', data bytes, // a trailing '#', and a two digit checksum. minimum valid body is the empty response '$#00' // https://developer.apple.com/library/archive/documentation/DeveloperTools/gdb/gdb/gdb_33.html - const packetData = this.buffer.toString().match('\\$.*#[0-9a-f]{2}'); - if (packetData == null) { - return; // incomplete body, wait for more - } + const packetData = this.buffer.toString().match('\\$.*#[0-9a-f]{2}') + if (packetData == null) + return // incomplete body, wait for more + // extract the body and update the buffer - const body = Buffer.from(packetData[0]); - this.buffer = this.buffer.slice(this.headerSize + body.length); + const body = Buffer.from(packetData[0]) + this.buffer = this.buffer.slice(this.headerSize + body.length) // parse the payload and recurse if there is more data to process - this.callback(this.parseBody(body)); - if (this.buffer.length) { - this.onData(); - } + this.callback(this.parseBody(body)) + if (this.buffer.length) + this.onData() } - } catch (err) { - this.callback(null, err); + } + catch (err) { + this.callback(null, err) } } parseHeader(data: Buffer) { - if (data[0] !== ACK_SUCCESS) { - throw new Error('Unsuccessful debugserver response'); - } // TODO: retry? - return -1; + if (data[0] !== ACK_SUCCESS) + throw new Error('Unsuccessful debugserver response') + // TODO: retry? + return -1 } parseBody(buffer: Buffer) { - debug(`Response body: ${buffer.toString()}`); + debug(`Response body: ${buffer.toString()}`) // check for checksum - const checksum = buffer.slice(-3).toString(); + const checksum = buffer.slice(-3).toString() if (checksum.match(/#[0-9a-f]{2}/)) { // remove '$' prefix and checksum - const msg = buffer.slice(1, -3).toString(); - if (validateChecksum(checksum, msg)) { - return msg; - } else { - throw new Error('Invalid checksum received from debugserver'); - } - } else { - throw new Error("Didn't receive checksum"); + const msg = buffer.slice(1, -3).toString() + if (validateChecksum(checksum, msg)) + return msg + else + throw new Error('Invalid checksum received from debugserver') + } + else { + throw new Error('Didn\'t receive checksum') } } } export class GDBProtocolWriter implements ProtocolWriter { write(socket: net.Socket, msg: GDBMessage) { - const { cmd, args } = msg; - debug(`Socket write: ${cmd}, args: ${args}`); + const { cmd, args } = msg + debug(`Socket write: ${cmd}, args: ${args}`) // hex encode and concat all args const encodedArgs = args .map(arg => Buffer.from(arg).toString('hex')) .join() - .toUpperCase(); - const checksumStr = calculateChecksum(cmd + encodedArgs); - const formattedCmd = `$${cmd}${encodedArgs}#${checksumStr}`; - socket.write(formattedCmd); + .toUpperCase() + const checksumStr = calculateChecksum(cmd + encodedArgs) + const formattedCmd = `$${cmd}${encodedArgs}#${checksumStr}` + socket.write(formattedCmd) } } // hex value of (sum of cmd chars mod 256) function calculateChecksum(cmdStr: string) { - let checksum = 0; - for (let i = 0; i < cmdStr.length; i++) { - checksum += cmdStr.charCodeAt(i); - } - let result = (checksum % 256).toString(16); + let checksum = 0 + for (let i = 0; i < cmdStr.length; i++) + checksum += cmdStr.charCodeAt(i) + + let result = (checksum % 256).toString(16) // pad if necessary - if (result.length === 1) { - result = `0${result}`; - } - return result; + if (result.length === 1) + result = `0${result}` + + return result } function validateChecksum(checksum: string, msg: string) { // remove '#' from checksum - const checksumVal = checksum.slice(1); + const checksumVal = checksum.slice(1) // remove '$' from msg and calculate its checksum - const computedChecksum = calculateChecksum(msg); - debug(`Checksum: ${checksumVal}, computed checksum: ${computedChecksum}`); - return checksumVal === computedChecksum; + const computedChecksum = calculateChecksum(msg) + debug(`Checksum: ${checksumVal}, computed checksum: ${computedChecksum}`) + return checksumVal === computedChecksum } diff --git a/src/ios/lib/protocol/index.ts b/src/ios/lib/protocol/index.ts index b5e45a7..99e9c11 100644 --- a/src/ios/lib/protocol/index.ts +++ b/src/ios/lib/protocol/index.ts @@ -1,5 +1,5 @@ -export * from './protocol'; -export * from './afc'; -export * from './gdb'; -export * from './lockdown'; -export * from './usbmux'; +export * from './protocol' +export * from './afc' +export * from './gdb' +export * from './lockdown' +export * from './usbmux' diff --git a/src/ios/lib/protocol/lockdown.ts b/src/ios/lib/protocol/lockdown.ts index 2260c94..6ebc904 100644 --- a/src/ios/lib/protocol/lockdown.ts +++ b/src/ios/lib/protocol/lockdown.ts @@ -1,50 +1,50 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; -import * as plist from 'plist'; +import type * as net from 'node:net' +import Debug from 'debug' +import * as plist from 'plist' -import { IOSLibError } from '../lib-errors'; +import { IOSLibError } from '../lib-errors' -import type { ProtocolWriter } from './protocol'; +import type { ProtocolWriter } from './protocol' import { PlistProtocolReader, ProtocolClient, ProtocolReaderFactory, -} from './protocol'; +} from './protocol' -const debug = Debug('native-run:ios:lib:protocol:lockdown'); -export const LOCKDOWN_HEADER_SIZE = 4; +const debug = Debug('native-run:ios:lib:protocol:lockdown') +export const LOCKDOWN_HEADER_SIZE = 4 export interface LockdownCommand { - Command: string; - [key: string]: any; + Command: string + [key: string]: any } export interface LockdownResponse { - Status: string; - [key: string]: any; + Status: string + [key: string]: any } export interface LockdownErrorResponse { - Error: string; + Error: string } export interface LockdownRequest { - Request: string; - [key: string]: any; + Request: string + [key: string]: any } function isDefined(val: any) { - return typeof val !== 'undefined'; + return typeof val !== 'undefined' } export function isLockdownResponse(resp: any): resp is LockdownResponse { - return isDefined(resp.Status); + return isDefined(resp.Status) } export function isLockdownErrorResponse( resp: any, ): resp is LockdownErrorResponse { - return isDefined(resp.Error); + return isDefined(resp.Error) } export class LockdownProtocolClient< @@ -55,40 +55,39 @@ export class LockdownProtocolClient< socket, new ProtocolReaderFactory(LockdownProtocolReader), new LockdownProtocolWriter(), - ); + ) } } export class LockdownProtocolReader extends PlistProtocolReader { constructor(callback: (data: any) => any) { - super(LOCKDOWN_HEADER_SIZE, callback); + super(LOCKDOWN_HEADER_SIZE, callback) } parseHeader(data: Buffer) { - return data.readUInt32BE(0); + return data.readUInt32BE(0) } parseBody(data: Buffer) { - const resp = super.parseBody(data); - debug(`Response: ${JSON.stringify(resp)}`); + const resp = super.parseBody(data) + debug(`Response: ${JSON.stringify(resp)}`) if (isLockdownErrorResponse(resp)) { - if (resp.Error === 'DeviceLocked') { - throw new IOSLibError('Device is currently locked.', 'DeviceLocked'); - } + if (resp.Error === 'DeviceLocked') + throw new IOSLibError('Device is currently locked.', 'DeviceLocked') - throw new Error(resp.Error); + throw new Error(resp.Error) } - return resp; + return resp } } export class LockdownProtocolWriter implements ProtocolWriter { write(socket: net.Socket, plistData: any) { - debug(`socket write: ${JSON.stringify(plistData)}`); - const plistMessage = plist.build(plistData); - const header = Buffer.alloc(LOCKDOWN_HEADER_SIZE); - header.writeUInt32BE(plistMessage.length, 0); - socket.write(header); - socket.write(plistMessage); + debug(`socket write: ${JSON.stringify(plistData)}`) + const plistMessage = plist.build(plistData) + const header = Buffer.alloc(LOCKDOWN_HEADER_SIZE) + header.writeUInt32BE(plistMessage.length, 0) + socket.write(header) + socket.write(plistMessage) } } diff --git a/src/ios/lib/protocol/protocol.ts b/src/ios/lib/protocol/protocol.ts index 8235823..945db84 100644 --- a/src/ios/lib/protocol/protocol.ts +++ b/src/ios/lib/protocol/protocol.ts @@ -1,10 +1,10 @@ -import * as bplistParser from 'bplist-parser'; -import type * as net from 'net'; -import * as plist from 'plist'; +import type net from 'node:net' +import bplistParser from 'bplist-parser' +import plist from 'plist' -const BPLIST_MAGIC = Buffer.from('bplist00'); +const BPLIST_MAGIC = Buffer.from('bplist00') -export type ProtocolReaderCallback = (resp: any, err?: Error) => void; +export type ProtocolReaderCallback = (resp: any, err?: Error) => void export class ProtocolReaderFactory { constructor( @@ -12,81 +12,81 @@ export class ProtocolReaderFactory { ) {} create(callback: (resp: any, err?: Error) => void): T { - return new this.ProtocolReader(callback); + return new this.ProtocolReader(callback) } } export abstract class ProtocolReader { - protected body!: Buffer; // TODO: ! -> ? - protected bodyLength!: number; // TODO: ! -> ? - protected buffer = Buffer.alloc(0); + protected body!: Buffer // TODO: ! -> ? + protected bodyLength!: number // TODO: ! -> ? + protected buffer = Buffer.alloc(0) constructor( protected headerSize: number, protected callback: ProtocolReaderCallback, ) { - this.onData = this.onData.bind(this); + this.onData = this.onData.bind(this) } /** Returns length of body, or -1 if header doesn't contain length */ - protected abstract parseHeader(data: Buffer): number; - protected abstract parseBody(data: Buffer): any; + protected abstract parseHeader(data: Buffer): number + protected abstract parseBody(data: Buffer): any onData(data?: Buffer) { try { // if there's data, add it on to existing buffer - this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer; + this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer // we haven't gotten the body length from the header yet if (!this.bodyLength) { if (this.buffer.length < this.headerSize) { // partial header, wait for rest - return; + return } - this.bodyLength = this.parseHeader(this.buffer); + this.bodyLength = this.parseHeader(this.buffer) // move on to body - this.buffer = this.buffer.slice(this.headerSize); + this.buffer = this.buffer.slice(this.headerSize) if (!this.buffer.length) { // only got header, wait for body - return; + return } } if (this.buffer.length < this.bodyLength) { // wait for rest of body - return; + return } if (this.bodyLength === -1) { - this.callback(this.parseBody(this.buffer)); - this.buffer = Buffer.alloc(0); - } else { - this.body = this.buffer.slice(0, this.bodyLength); - this.bodyLength -= this.body.length; - if (!this.bodyLength) { - this.callback(this.parseBody(this.body)); - } - this.buffer = this.buffer.slice(this.body.length); + this.callback(this.parseBody(this.buffer)) + this.buffer = Buffer.alloc(0) + } + else { + this.body = this.buffer.slice(0, this.bodyLength) + this.bodyLength -= this.body.length + if (!this.bodyLength) + this.callback(this.parseBody(this.body)) + + this.buffer = this.buffer.slice(this.body.length) // There are multiple messages here, call parse again - if (this.buffer.length) { - this.onData(); - } + if (this.buffer.length) + this.onData() } - } catch (err) { - this.callback(null, err); + } + catch (err: any) { + this.callback(null, err) } } } export abstract class PlistProtocolReader extends ProtocolReader { protected parseBody(body: Buffer) { - if (BPLIST_MAGIC.compare(body, 0, 8) === 0) { - return bplistParser.parseBuffer(body); - } else { - return plist.parse(body.toString('utf8')); - } + if (BPLIST_MAGIC.compare(body, 0, 8) === 0) + return bplistParser.parseBuffer(body) + else + return plist.parse(body.toString('utf8')) } } export interface ProtocolWriter { - write(sock: net.Socket, msg: any): void; + write(sock: net.Socket, msg: any): void } export abstract class ProtocolClient { @@ -96,11 +96,11 @@ export abstract class ProtocolClient { protected writer: ProtocolWriter, ) {} - sendMessage(msg: MessageType): Promise; + sendMessage(msg: MessageType): Promise sendMessage( msg: MessageType, callback: (response: ResponseType, resolve: any, reject: any) => void, - ): Promise; + ): Promise sendMessage( msg: MessageType, callback?: (response: ResponseType, resolve: any, reject: any) => void, @@ -109,29 +109,30 @@ export abstract class ProtocolClient { const reader = this.readerFactory.create( async (resp: ResponseType, err?: Error) => { if (err) { - reject(err); - return; + reject(err) + return } if (callback) { callback( resp, (value: any) => { - this.socket.removeListener('data', reader.onData); - resolve(value); + this.socket.removeListener('data', reader.onData) + resolve(value) }, reject, - ); - } else { - this.socket.removeListener('data', reader.onData); - resolve(resp); + ) + } + else { + this.socket.removeListener('data', reader.onData) + resolve(resp) } }, - ); - this.socket.on('error', err => { - throw err; - }); - this.socket.on('data', reader.onData); - this.writer.write(this.socket, msg); - }); + ) + this.socket.on('error', (err) => { + throw err + }) + this.socket.on('data', reader.onData) + this.writer.write(this.socket, msg) + }) } } diff --git a/src/ios/lib/protocol/usbmux.ts b/src/ios/lib/protocol/usbmux.ts index f8ce864..76f7f4f 100644 --- a/src/ios/lib/protocol/usbmux.ts +++ b/src/ios/lib/protocol/usbmux.ts @@ -1,21 +1,21 @@ -import * as Debug from 'debug'; -import type * as net from 'net'; -import * as plist from 'plist'; +import type * as net from 'node:net' +import Debug from 'debug' +import * as plist from 'plist' -import type { ProtocolWriter } from './protocol'; +import type { ProtocolWriter } from './protocol' import { PlistProtocolReader, ProtocolClient, ProtocolReaderFactory, -} from './protocol'; +} from './protocol' -const debug = Debug('native-run:ios:lib:protocol:usbmux'); +const debug = Debug('native-run:ios:lib:protocol:usbmux') -export const USBMUXD_HEADER_SIZE = 16; +export const USBMUXD_HEADER_SIZE = 16 export interface UsbmuxMessage { - messageType: string; - extraFields?: { [key: string]: any }; + messageType: string + extraFields?: { [key: string]: any } } export class UsbmuxProtocolClient extends ProtocolClient { @@ -24,33 +24,33 @@ export class UsbmuxProtocolClient extends ProtocolClient { socket, new ProtocolReaderFactory(UsbmuxProtocolReader), new UsbmuxProtocolWriter(), - ); + ) } } export class UsbmuxProtocolReader extends PlistProtocolReader { constructor(callback: (data: any) => any) { - super(USBMUXD_HEADER_SIZE, callback); + super(USBMUXD_HEADER_SIZE, callback) } parseHeader(data: Buffer) { - return data.readUInt32LE(0) - USBMUXD_HEADER_SIZE; + return data.readUInt32LE(0) - USBMUXD_HEADER_SIZE } parseBody(data: Buffer) { - const resp = super.parseBody(data); - debug(`Response: ${JSON.stringify(resp)}`); - return resp; + const resp = super.parseBody(data) + debug(`Response: ${JSON.stringify(resp)}`) + return resp } } export class UsbmuxProtocolWriter implements ProtocolWriter { - private useTag = 0; + private useTag = 0 write(socket: net.Socket, msg: UsbmuxMessage) { // TODO Usbmux message type - debug(`socket write: ${JSON.stringify(msg)}`); - const { messageType, extraFields } = msg; + debug(`socket write: ${JSON.stringify(msg)}`) + const { messageType, extraFields } = msg const plistMessage = plist.build({ BundleID: 'io.ionic.native-run', // TODO ClientVersionString: 'usbmux.js', // TODO @@ -58,18 +58,18 @@ export class UsbmuxProtocolWriter implements ProtocolWriter { ProgName: 'native-run', // TODO kLibUSBMuxVersion: 3, ...extraFields, - }); + }) - const dataSize = plistMessage ? plistMessage.length : 0; - const protocolVersion = 1; - const messageCode = 8; + const dataSize = plistMessage ? plistMessage.length : 0 + const protocolVersion = 1 + const messageCode = 8 - const header = Buffer.alloc(USBMUXD_HEADER_SIZE); - header.writeUInt32LE(USBMUXD_HEADER_SIZE + dataSize, 0); - header.writeUInt32LE(protocolVersion, 4); - header.writeUInt32LE(messageCode, 8); - header.writeUInt32LE(this.useTag++, 12); // TODO - socket.write(header); - socket.write(plistMessage); + const header = Buffer.alloc(USBMUXD_HEADER_SIZE) + header.writeUInt32LE(USBMUXD_HEADER_SIZE + dataSize, 0) + header.writeUInt32LE(protocolVersion, 4) + header.writeUInt32LE(messageCode, 8) + header.writeUInt32LE(this.useTag++, 12) // TODO + socket.write(header) + socket.write(plistMessage) } } diff --git a/src/ios/list.ts b/src/ios/list.ts index 816a4e2..c552338 100644 --- a/src/ios/list.ts +++ b/src/ios/list.ts @@ -1,41 +1,43 @@ -import type { Exception } from '../errors'; -import type { Target, Targets } from '../utils/list'; -import { formatTargets } from '../utils/list'; +import type { Exception } from '../errors' +import type { Target, Targets } from '../utils/list' +import { formatTargets } from '../utils/list' -import type { DeviceValues } from './lib'; -import { getConnectedDevices } from './utils/device'; -import type { Simulator } from './utils/simulator'; -import { getSimulators } from './utils/simulator'; +import type { DeviceValues } from './lib' +import { getConnectedDevices } from './utils/device' +import type { Simulator } from './utils/simulator' +import { getSimulators } from './utils/simulator' export async function run(args: readonly string[]): Promise { - const targets = await list(args); - process.stdout.write(`\n${formatTargets(args, targets)}\n`); + const targets = await list(args) + process.stdout.write(`\n${formatTargets(args, targets)}\n`) } export async function list(args: readonly string[]): Promise { - const errors: Exception[] = []; + const errors: Exception[] = [] const [devices, virtualDevices] = await Promise.all([ (async () => { try { - const devices = await getConnectedDevices(); - return devices.map(deviceToTarget); - } catch (e) { - errors.push(e); - return []; + const devices = await getConnectedDevices() + return devices.map(deviceToTarget) + } + catch (e) { + errors.push(e) + return [] } })(), (async () => { try { - const simulators = await getSimulators(); - return simulators.map(simulatorToTarget); - } catch (e) { - errors.push(e); - return []; + const simulators = await getSimulators() + return simulators.map(simulatorToTarget) + } + catch (e) { + errors.push(e) + return [] } })(), - ]); + ]) - return { devices, virtualDevices, errors }; + return { devices, virtualDevices, errors } } function deviceToTarget(device: DeviceValues): Target { @@ -45,7 +47,7 @@ function deviceToTarget(device: DeviceValues): Target { model: device.ProductType, sdkVersion: device.ProductVersion, id: device.UniqueDeviceID, - }; + } } function simulatorToTarget(simulator: Simulator): Target { @@ -54,5 +56,5 @@ function simulatorToTarget(simulator: Simulator): Target { name: simulator.name, sdkVersion: simulator.runtime.version, id: simulator.udid, - }; + } } diff --git a/src/ios/run.ts b/src/ios/run.ts index 93e72e6..16da984 100644 --- a/src/ios/run.ts +++ b/src/ios/run.ts @@ -1,7 +1,7 @@ -import { remove } from '@ionic/utils-fs'; -import * as Debug from 'debug'; -import { existsSync, mkdtempSync } from 'fs'; -import * as path from 'path'; +import { existsSync, mkdtempSync } from 'node:fs' +import * as path from 'node:path' +import { remove } from '@ionic/utils-fs' +import Debug from 'debug' import { CLIException, @@ -9,27 +9,27 @@ import { ERR_DEVICE_LOCKED, ERR_TARGET_NOT_FOUND, IOSRunException, -} from '../errors'; -import { getOptionValue } from '../utils/cli'; -import { wait } from '../utils/process'; +} from '../errors' +import { getOptionValue } from '../utils/cli' +import { wait } from '../utils/process' -import type { DeviceValues } from './lib'; -import { IOSLibError } from './lib/lib-errors'; -import { getBundleId, unzipIPA } from './utils/app'; -import { getConnectedDevices, runOnDevice } from './utils/device'; -import type { SimulatorResult } from './utils/simulator'; -import { getSimulators, runOnSimulator } from './utils/simulator'; +import type { DeviceValues } from './lib' +import { IOSLibError } from './lib/lib-errors' +import { getBundleId, unzipIPA } from './utils/app' +import { getConnectedDevices, runOnDevice } from './utils/device' +import type { SimulatorResult } from './utils/simulator' +import { getSimulators, runOnSimulator } from './utils/simulator' -const debug = Debug('native-run:ios:run'); +const debug = Debug('native-run:ios:run') interface IOSRunConfig { - udid?: string; - devices: DeviceValues[]; - simulators: SimulatorResult[]; - appPath: string; - bundleId: string; - waitForApp: boolean; - preferSimulator: boolean; + udid?: string + devices: DeviceValues[] + simulators: SimulatorResult[] + appPath: string + bundleId: string + waitForApp: boolean + preferSimulator: boolean } async function runIpaOrAppFile({ @@ -43,101 +43,108 @@ async function runIpaOrAppFile({ }: IOSRunConfig): Promise { if (udid) { if (devices.find(d => d.UniqueDeviceID === udid)) { - await runOnDevice(udid, appPath, bundleId, waitForApp); - } else if (simulators.find(s => s.udid === udid)) { - await runOnSimulator(udid, appPath, bundleId, waitForApp); - } else { + await runOnDevice(udid, appPath, bundleId, waitForApp) + } + else if (simulators.find(s => s.udid === udid)) { + await runOnSimulator(udid, appPath, bundleId, waitForApp) + } + else { throw new IOSRunException( `No device or simulator with UDID "${udid}" found`, ERR_TARGET_NOT_FOUND, - ); + ) } - } else if (devices.length && !preferSimulator) { + } + else if (devices.length && !preferSimulator) { // no udid, use first connected device - await runOnDevice(devices[0].UniqueDeviceID, appPath, bundleId, waitForApp); - } else { + await runOnDevice(devices[0].UniqueDeviceID, appPath, bundleId, waitForApp) + } + else { // use default sim await runOnSimulator( simulators[simulators.length - 1].udid, appPath, bundleId, waitForApp, - ); + ) } } async function runIpaOrAppFileOnInterval(config: IOSRunConfig): Promise { - const maxRetryCount = 12; // 1 minute - const retryInterval = 5000; // 5 seconds - let error: Error | undefined; - let retryCount = 0; + const maxRetryCount = 12 // 1 minute + const retryInterval = 5000 // 5 seconds + let error: Error | undefined + let retryCount = 0 const retry = async () => { - process.stderr.write('Please unlock your device. Waiting 5 seconds...\n'); - retryCount++; - await wait(retryInterval); - await run(); - }; + process.stderr.write('Please unlock your device. Waiting 5 seconds...\n') + retryCount++ + await wait(retryInterval) + // TODO: 'run' was used before it was defined. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + await run() + } const run = async () => { try { - await runIpaOrAppFile(config); - } catch (err: any) { + await runIpaOrAppFile(config) + } + catch (err: any) { if ( - err instanceof IOSLibError && - err.code == 'DeviceLocked' && - retryCount < maxRetryCount + err instanceof IOSLibError + && err.code === 'DeviceLocked' + && retryCount < maxRetryCount ) { - await retry(); - } else { + await retry() + } + else { if (retryCount >= maxRetryCount) { error = new IOSRunException( - `Device still locked after 1 minute. Aborting.`, + 'Device still locked after 1 minute. Aborting.', ERR_DEVICE_LOCKED, - ); - } else { - error = err; + ) + } + else { + error = err } } } - }; + } - await run(); + await run() - if (error) { - throw error; - } + if (error) + throw error } export async function run(args: readonly string[]): Promise { - let appPath = getOptionValue(args, '--app'); - if (!appPath) { - throw new CLIException('--app is required', ERR_BAD_INPUT); - } - const udid = getOptionValue(args, '--target'); - const preferSimulator = args.includes('--virtual'); - const waitForApp = args.includes('--connect'); - const isIPA = appPath.endsWith('.ipa'); + let appPath = getOptionValue(args, '--app') + if (!appPath) + throw new CLIException('--app is required', ERR_BAD_INPUT) - if (!existsSync(appPath)) { - throw new IOSRunException(`Path '${appPath}' not found`); - } + const udid = getOptionValue(args, '--target') + const preferSimulator = args.includes('--virtual') + const waitForApp = args.includes('--connect') + const isIPA = appPath.endsWith('.ipa') + + if (!existsSync(appPath)) + throw new IOSRunException(`Path '${appPath}' not found`) try { if (isIPA) { - const { tmpdir } = await import('os'); - const tempDir = mkdtempSync(`${tmpdir()}${path.sep}`); - debug(`Unzipping .ipa to ${tempDir}`); - const appDir = await unzipIPA(appPath, tempDir); - appPath = path.join(tempDir, appDir); + const { tmpdir } = await import('node:os') + const tempDir = mkdtempSync(`${tmpdir()}${path.sep}`) + debug(`Unzipping .ipa to ${tempDir}`) + const appDir = await unzipIPA(appPath, tempDir) + appPath = path.join(tempDir, appDir) } - const bundleId = await getBundleId(appPath); + const bundleId = await getBundleId(appPath) const [devices, simulators] = await Promise.all([ getConnectedDevices(), getSimulators(), - ]); + ]) // try to run on device or simulator with udid const config: IOSRunConfig = { udid, @@ -147,14 +154,16 @@ export async function run(args: readonly string[]): Promise { bundleId, waitForApp, preferSimulator, - }; + } - await runIpaOrAppFileOnInterval(config); - } finally { + await runIpaOrAppFileOnInterval(config) + } + finally { if (isIPA) { try { - await remove(appPath); - } catch { + await remove(appPath) + } + catch { // ignore } } diff --git a/src/ios/utils/app.ts b/src/ios/utils/app.ts index 4fd5766..3b8c4f8 100644 --- a/src/ios/utils/app.ts +++ b/src/ios/utils/app.ts @@ -1,62 +1,62 @@ -import { mkdirp } from '@ionic/utils-fs'; -import * as Debug from 'debug'; -import { createWriteStream } from 'fs'; -import * as path from 'path'; +import { createWriteStream } from 'node:fs' +import * as path from 'node:path' +import { mkdirp } from '@ionic/utils-fs' +import Debug from 'debug' -import { Exception } from '../../errors'; -import { execFile } from '../../utils/process'; -import { unzip } from '../../utils/unzip'; +import { Exception } from '../../errors' +import { execFile } from '../../utils/process' +import { unzip } from '../../utils/unzip' -const debug = Debug('native-run:ios:utils:app'); +const debug = Debug('native-run:ios:utils:app') // TODO: cross platform? Use plist/bplist export async function getBundleId(appPath: string) { - const plistPath = path.resolve(appPath, 'Info.plist'); + const plistPath = path.resolve(appPath, 'Info.plist') try { const { stdout } = await execFile( '/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', plistPath], { encoding: 'utf8' }, - ); - if (stdout) { - return stdout.trim(); - } - } catch { + ) + if (stdout) + return stdout.trim() + } + catch { // ignore } - throw new Exception('Unable to get app bundle identifier'); + throw new Exception('Unable to get app bundle identifier') } export async function unzipIPA(ipaPath: string, destPath: string) { - let error: Error | undefined; - let appPath = ''; + let error: Error | undefined + let appPath = '' await unzip(ipaPath, async (entry, zipfile, openReadStream) => { - debug(`Unzip: ${entry.fileName}`); - const dest = path.join(destPath, entry.fileName); + debug(`Unzip: ${entry.fileName}`) + const dest = path.join(destPath, entry.fileName) if (entry.fileName.endsWith('/')) { - await mkdirp(dest); - if (entry.fileName.endsWith('.app/')) { - appPath = entry.fileName; - } - zipfile.readEntry(); - } else { - await mkdirp(path.dirname(dest)); - const readStream = await openReadStream(entry); - readStream.on('error', (err: Error) => (error = err)); + await mkdirp(dest) + if (entry.fileName.endsWith('.app/')) + appPath = entry.fileName + + zipfile.readEntry() + } + else { + await mkdirp(path.dirname(dest)) + const readStream = await openReadStream(entry) + readStream.on('error', (err: Error) => (error = err)) readStream.on('end', () => { - zipfile.readEntry(); - }); - readStream.pipe(createWriteStream(dest)); + zipfile.readEntry() + }) + readStream.pipe(createWriteStream(dest)) } - }); + }) - if (error) { - throw error; - } + if (error) + throw error - if (!appPath) { - throw new Exception('Unable to determine .app directory from .ipa'); - } - return appPath; + if (!appPath) + throw new Exception('Unable to determine .app directory from .ipa') + + return appPath } diff --git a/src/ios/utils/device.ts b/src/ios/utils/device.ts index 6452ed8..000579d 100644 --- a/src/ios/utils/device.ts +++ b/src/ios/utils/device.ts @@ -1,37 +1,37 @@ -import * as Debug from 'debug'; -import { readFileSync } from 'fs'; -import * as path from 'path'; +import { readFileSync } from 'node:fs' +import * as path from 'node:path' +import Debug from 'debug' -import { Exception } from '../../errors'; -import { onBeforeExit, wait } from '../../utils/process'; -import type { DeviceValues, IPLookupResult } from '../lib'; +import { Exception } from '../../errors' +import { onBeforeExit, wait } from '../../utils/process' +import type { DeviceValues, IPLookupResult } from '../lib' import { AFCError, AFC_STATUS, ClientManager, LockdowndClient, UsbmuxdClient, -} from '../lib'; +} from '../lib' -import { getDeveloperDiskImagePath } from './xcode'; +import { getDeveloperDiskImagePath } from './xcode' -const debug = Debug('native-run:ios:utils:device'); +const debug = Debug('native-run:ios:utils:device') export async function getConnectedDevices() { - const usbmuxClient = new UsbmuxdClient(UsbmuxdClient.connectUsbmuxdSocket()); - const usbmuxDevices = await usbmuxClient.getDevices(); - usbmuxClient.socket.end(); + const usbmuxClient = new UsbmuxdClient(UsbmuxdClient.connectUsbmuxdSocket()) + const usbmuxDevices = await usbmuxClient.getDevices() + usbmuxClient.socket.end() return Promise.all( usbmuxDevices.map(async (d): Promise => { const socket = await new UsbmuxdClient( UsbmuxdClient.connectUsbmuxdSocket(), - ).connect(d, 62078); - const device = await new LockdowndClient(socket).getAllValues(); - socket.end(); - return device; + ).connect(d, 62078) + const device = await new LockdowndClient(socket).getAllValues() + socket.end() + return device }), - ); + ) } export async function runOnDevice( @@ -40,65 +40,65 @@ export async function runOnDevice( bundleId: string, waitForApp: boolean, ) { - const clientManager = await ClientManager.create(udid); + const clientManager = await ClientManager.create(udid) try { - await mountDeveloperDiskImage(clientManager); + await mountDeveloperDiskImage(clientManager) - const packageName = path.basename(appPath); - const destPackagePath = path.join('PublicStaging', packageName); + const packageName = path.basename(appPath) + const destPackagePath = path.join('PublicStaging', packageName) - await uploadApp(clientManager, appPath, destPackagePath); + await uploadApp(clientManager, appPath, destPackagePath) - const installer = await clientManager.getInstallationProxyClient(); - await installer.installApp(destPackagePath, bundleId); + const installer = await clientManager.getInstallationProxyClient() + await installer.installApp(destPackagePath, bundleId) - const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]); + const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]) // launch fails with EBusy or ENotFound if you try to launch immediately after install - await wait(200); - const debugServerClient = await launchApp(clientManager, appInfo); + await wait(200) + const debugServerClient = await launchApp(clientManager, appInfo) if (waitForApp) { onBeforeExit(async () => { // causes continue() to return - debugServerClient.halt(); + debugServerClient.halt() // give continue() time to return response - await wait(64); - }); + await wait(64) + }) - debug(`Waiting for app to close...\n`); - const result = await debugServerClient.continue(); + debug('Waiting for app to close...\n') + const result = await debugServerClient.continue() // TODO: I have no idea what this packet means yet (successful close?) // if not a close (ie, most likely due to halt from onBeforeExit), then kill the app - if (result !== 'W00') { - await debugServerClient.kill(); - } + if (result !== 'W00') + await debugServerClient.kill() } - } finally { - clientManager.end(); + } + finally { + clientManager.end() } } async function mountDeveloperDiskImage(clientManager: ClientManager) { - const imageMounter = await clientManager.getMobileImageMounterClient(); + const imageMounter = await clientManager.getMobileImageMounterClient() // Check if already mounted. If not, mount. if (!(await imageMounter.lookupImage()).ImageSignature) { // verify DeveloperDiskImage exists (TODO: how does this work on Windows/Linux?) // TODO: if windows/linux, download? const version = await ( await clientManager.getLockdowndClient() - ).getValue('ProductVersion'); - const developerDiskImagePath = await getDeveloperDiskImagePath(version); + ).getValue('ProductVersion') + const developerDiskImagePath = await getDeveloperDiskImagePath(version) const developerDiskImageSig = readFileSync( `${developerDiskImagePath}.signature`, - ); + ) await imageMounter.uploadImage( developerDiskImagePath, developerDiskImageSig, - ); + ) await imageMounter.mountImage( developerDiskImagePath, developerDiskImageSig, - ); + ) } } @@ -107,41 +107,43 @@ async function uploadApp( srcPath: string, destinationPath: string, ) { - const afcClient = await clientManager.getAFCClient(); + const afcClient = await clientManager.getAFCClient() try { - await afcClient.getFileInfo('PublicStaging'); - } catch (err) { - if (err instanceof AFCError && err.status === AFC_STATUS.OBJECT_NOT_FOUND) { - await afcClient.makeDirectory('PublicStaging'); - } else { - throw err; - } + await afcClient.getFileInfo('PublicStaging') + } + catch (err) { + if (err instanceof AFCError && err.status === AFC_STATUS.OBJECT_NOT_FOUND) + await afcClient.makeDirectory('PublicStaging') + else + throw err } - await afcClient.uploadDirectory(srcPath, destinationPath); + await afcClient.uploadDirectory(srcPath, destinationPath) } async function launchApp( clientManager: ClientManager, appInfo: IPLookupResult[string], ) { - let tries = 0; + let tries = 0 while (tries < 3) { - const debugServerClient = await clientManager.getDebugserverClient(); - await debugServerClient.setMaxPacketSize(1024); - await debugServerClient.setWorkingDir(appInfo.Container); - await debugServerClient.launchApp(appInfo.Path, appInfo.CFBundleExecutable); + const debugServerClient = await clientManager.getDebugserverClient() + await debugServerClient.setMaxPacketSize(1024) + await debugServerClient.setWorkingDir(appInfo.Container) + await debugServerClient.launchApp(appInfo.Path, appInfo.CFBundleExecutable) - const result = await debugServerClient.checkLaunchSuccess(); + const result = await debugServerClient.checkLaunchSuccess() if (result === 'OK') { - return debugServerClient; - } else if (result === 'EBusy' || result === 'ENotFound') { - debug('Device busy or app not found, trying to launch again in .5s...'); - tries++; - debugServerClient.socket.end(); - await wait(500); - } else { - throw new Exception(`There was an error launching app: ${result}`); + return debugServerClient + } + else if (result === 'EBusy' || result === 'ENotFound') { + debug('Device busy or app not found, trying to launch again in .5s...') + tries++ + debugServerClient.socket.end() + await wait(500) + } + else { + throw new Exception(`There was an error launching app: ${result}`) } } - throw new Exception('Unable to launch app, number of tries exceeded'); + throw new Exception('Unable to launch app, number of tries exceeded') } diff --git a/src/ios/utils/simulator.ts b/src/ios/utils/simulator.ts index 0ec59c1..d0c82d9 100644 --- a/src/ios/utils/simulator.ts +++ b/src/ios/utils/simulator.ts @@ -1,68 +1,66 @@ -import { spawnSync } from 'child_process'; // TODO: need cross-spawn for windows? -import * as Debug from 'debug'; +import { spawnSync } from 'node:child_process' // TODO: need cross-spawn for windows? +import Debug from 'debug' -import { Exception } from '../../errors'; -import { log } from '../../utils/log'; -import { onBeforeExit } from '../../utils/process'; +import { Exception } from '../../errors' +import { log } from '../../utils/log' +import { onBeforeExit } from '../../utils/process' -import { getXCodePath, getXcodeVersionInfo } from './xcode'; +import { getXCodePath, getXcodeVersionInfo } from './xcode' -const debug = Debug('native-run:ios:utils:simulator'); +const debug = Debug('native-run:ios:utils:simulator') export interface Simulator { - availability: '(available)' | '(unavailable)'; - isAvailable: boolean; - name: string; // "iPhone 5"; - state: string; // "Shutdown" - udid: string; - runtime: SimCtlRuntime; + availability: '(available)' | '(unavailable)' + isAvailable: boolean + name: string // "iPhone 5"; + state: string // "Shutdown" + udid: string + runtime: SimCtlRuntime } interface SimCtlRuntime { - readonly buildversion: string; // "14B72" - readonly availability: '(available)' | '(unavailable)'; - readonly name: string; // "iOS 10.1" - readonly identifier: string; // "com.apple.CoreSimulator.SimRuntime.iOS-10-1" - readonly version: string; // "10.1" + readonly buildversion: string // "14B72" + readonly availability: '(available)' | '(unavailable)' + readonly name: string // "iOS 10.1" + readonly identifier: string // "com.apple.CoreSimulator.SimRuntime.iOS-10-1" + readonly version: string // "10.1" } interface SimCtlType { - readonly name: string; // "iPhone 7" - readonly identifier: string; // "com.apple.CoreSimulator.SimDeviceType.iPhone-7" + readonly name: string // "iPhone 7" + readonly identifier: string // "com.apple.CoreSimulator.SimDeviceType.iPhone-7" } interface SimCtlOutput { readonly devices: { - readonly [key: string]: Simulator[]; - }; - readonly runtimes: SimCtlRuntime[]; - readonly devicetypes: SimCtlType[]; + readonly [key: string]: Simulator[] + } + readonly runtimes: SimCtlRuntime[] + readonly devicetypes: SimCtlType[] } export interface SimulatorResult extends Simulator { - runtime: SimCtlRuntime; + runtime: SimCtlRuntime } export async function getSimulators(): Promise { const simctl = spawnSync('xcrun', ['simctl', 'list', '--json'], { encoding: 'utf8', - }); - if (simctl.status) { - throw new Exception(`Unable to retrieve simulator list: ${simctl.stderr}`); - } + }) + if (simctl.status) + throw new Exception(`Unable to retrieve simulator list: ${simctl.stderr}`) - const [xcodeVersion] = getXcodeVersionInfo(); - if (Number(xcodeVersion) < 10) { - throw new Exception('native-run only supports Xcode 10 and later'); - } + const [xcodeVersion] = getXcodeVersionInfo() + if (Number(xcodeVersion) < 10) + throw new Exception('native-run only supports Xcode 10 and later') try { - const output: SimCtlOutput = JSON.parse(simctl.stdout); + const output: SimCtlOutput = JSON.parse(simctl.stdout) return output.runtimes .filter( runtime => - runtime.name.indexOf('watch') === -1 && - runtime.name.indexOf('tv') === -1, + !runtime.name.includes('watch') + && !runtime.name.includes('tv'), ) .map(runtime => (output.devices[runtime.identifier] || output.devices[runtime.name]) @@ -70,9 +68,10 @@ export async function getSimulators(): Promise { .map(device => ({ ...device, runtime })), ) .reduce((prev, next) => prev.concat(next)) // flatten - .sort((a, b) => (a.name < b.name ? -1 : 1)); - } catch (err) { - throw new Exception(`Unable to retrieve simulator list: ${err.message}`); + .sort((a, b) => (a.name < b.name ? -1 : 1)) + } + catch (err) { + throw new Exception(`Unable to retrieve simulator list: ${err.message}`) } } @@ -82,36 +81,36 @@ export async function runOnSimulator( bundleId: string, waitForApp: boolean, ) { - debug(`Booting simulator ${udid}`); + debug(`Booting simulator ${udid}`) const bootResult = spawnSync('xcrun', ['simctl', 'boot', udid], { encoding: 'utf8', - }); + }) // TODO: is there a better way to check this? if ( - bootResult.status && - !bootResult.stderr.includes( + bootResult.status + && !bootResult.stderr.includes( 'Unable to boot device in current state: Booted', ) ) { throw new Exception( `There was an error booting simulator: ${bootResult.stderr}`, - ); + ) } - debug(`Installing ${appPath} on ${udid}`); + debug(`Installing ${appPath} on ${udid}`) const installResult = spawnSync( 'xcrun', ['simctl', 'install', udid, appPath], { encoding: 'utf8' }, - ); + ) if (installResult.status) { throw new Exception( `There was an error installing app on simulator: ${installResult.stderr}`, - ); + ) } - const xCodePath = await getXCodePath(); - debug(`Running simulator ${udid}`); + const xCodePath = await getXCodePath() + debug(`Running simulator ${udid}`) const openResult = spawnSync( 'open', [ @@ -121,23 +120,23 @@ export async function runOnSimulator( udid, ], { encoding: 'utf8' }, - ); + ) if (openResult.status) { throw new Exception( `There was an error opening simulator: ${openResult.stderr}`, - ); + ) } - debug(`Launching ${appPath} on ${udid}`); + debug(`Launching ${appPath} on ${udid}`) const launchResult = spawnSync( 'xcrun', ['simctl', 'launch', udid, bundleId], { encoding: 'utf8' }, - ); + ) if (launchResult.status) { throw new Exception( `There was an error launching app on simulator: ${launchResult.stderr}`, - ); + ) } if (waitForApp) { @@ -146,19 +145,18 @@ export async function runOnSimulator( 'xcrun', ['simctl', 'terminate', udid, bundleId], { encoding: 'utf8' }, - ); - if (terminateResult.status) { - debug('Unable to terminate app on simulator'); - } - }); + ) + if (terminateResult.status) + debug('Unable to terminate app on simulator') + }) - log(`Waiting for app to close...\n`); - await waitForSimulatorClose(udid, bundleId); + log('Waiting for app to close...\n') + await waitForSimulatorClose(udid, bundleId) } } async function waitForSimulatorClose(udid: string, bundleId: string) { - return new Promise(resolve => { + return new Promise((resolve) => { // poll service list for bundle id const interval = setInterval(async () => { try { @@ -166,18 +164,19 @@ async function waitForSimulatorClose(udid: string, bundleId: string) { 'xcrun', ['simctl', 'spawn', udid, 'launchctl', 'list'], { encoding: 'utf8' }, - ); + ) // if bundle id isn't in list, app isn't running - if (data.stdout.indexOf(bundleId) === -1) { - clearInterval(interval); - resolve(); + if (!data.stdout.includes(bundleId)) { + clearInterval(interval) + resolve() } - } catch (e) { - debug('Error received from launchctl: %O', e); - debug('App %s no longer found in process list for %s', bundleId, udid); - clearInterval(interval); - resolve(); } - }, 500); - }); + catch (e) { + debug('Error received from launchctl: %O', e) + debug('App %s no longer found in process list for %s', bundleId, udid) + clearInterval(interval) + resolve() + } + }, 500) + }) } diff --git a/src/ios/utils/xcode.ts b/src/ios/utils/xcode.ts index 3a8aaf2..164da13 100644 --- a/src/ios/utils/xcode.ts +++ b/src/ios/utils/xcode.ts @@ -1,11 +1,11 @@ -import { readdir } from '@ionic/utils-fs'; -import { spawnSync } from 'child_process'; +import { spawnSync } from 'node:child_process' +import { readdir } from '@ionic/utils-fs' -import { Exception } from '../../errors'; -import { execFile } from '../../utils/process'; +import { Exception } from '../../errors' +import { execFile } from '../../utils/process' -type XcodeVersion = string; -type XcodeBuildVersion = string; +type XcodeVersion = string +type XcodeBuildVersion = string export function getXcodeVersionInfo(): readonly [ XcodeVersion, @@ -13,20 +13,20 @@ export function getXcodeVersionInfo(): readonly [ ] { const xcodeVersionInfo = spawnSync('xcodebuild', ['-version'], { encoding: 'utf8', - }); - if (xcodeVersionInfo.error) { - throw xcodeVersionInfo.error; - } + }) + if (xcodeVersionInfo.error) + throw xcodeVersionInfo.error try { - const trimmed = xcodeVersionInfo.stdout.trim().split('\n'); + const trimmed = xcodeVersionInfo.stdout.trim().split('\n') return ['Xcode ', 'Build version'].map((s, i) => trimmed[i].replace(s, ''), - ) as [string, string]; - } catch (error) { + ) as [string, string] + } + catch (error) { throw new Exception( `There was an error trying to retrieve the Xcode version: ${xcodeVersionInfo.stderr}`, - ); + ) } } @@ -34,32 +34,31 @@ export async function getXCodePath() { try { const { stdout } = await execFile('xcode-select', ['-p'], { encoding: 'utf8', - }); - if (stdout) { - return stdout.trim(); - } - } catch { + }) + if (stdout) + return stdout.trim() + } + catch { // ignore } - throw new Exception('Unable to get Xcode location. Is Xcode installed?'); + throw new Exception('Unable to get Xcode location. Is Xcode installed?') } export async function getDeveloperDiskImagePath(version: string) { - const xCodePath = await getXCodePath(); + const xCodePath = await getXCodePath() const versionDirs = await readdir( `${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`, - ); - const versionPrefix = version.match(/\d+\.\d+/); - if (versionPrefix === null) { - throw new Exception(`Invalid iOS version: ${version}`); - } + ) + const versionPrefix = version.match(/\d+\.\d+/) + if (versionPrefix === null) + throw new Exception(`Invalid iOS version: ${version}`) + // Can look like "11.2 (15C107)" for (const dir of versionDirs) { - if (dir.includes(versionPrefix[0])) { - return `${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/${dir}/DeveloperDiskImage.dmg`; - } + if (dir.includes(versionPrefix[0])) + return `${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/${dir}/DeveloperDiskImage.dmg` } throw new Exception( `Unable to find Developer Disk Image path for SDK ${version}. Do you have the right version of Xcode?`, - ); + ) } diff --git a/src/list.ts b/src/list.ts index c475290..a0a80a1 100644 --- a/src/list.ts +++ b/src/list.ts @@ -1,22 +1,23 @@ -import { stringify } from './utils/json'; -import type { Targets } from './utils/list'; -import { formatTargets } from './utils/list'; +import { stringify } from './utils/json' +import type { Targets } from './utils/list' +import { formatTargets } from './utils/list' export async function run(args: readonly string[]): Promise { const [ios, android] = await Promise.all([ (async (): Promise => { - const cmd = await import('./ios/list'); - return cmd.list(args); + const cmd = await import('./ios/list') + return cmd.list(args) })(), (async (): Promise => { - const cmd = await import('./android/list'); - return cmd.list(args); + const cmd = await import('./android/list') + return cmd.list(args) })(), - ]); + ]) if (args.includes('--json')) { - process.stdout.write(stringify({ ios, android })); - } else { + process.stdout.write(stringify({ ios, android })) + } + else { process.stdout.write(` iOS --- @@ -28,6 +29,6 @@ Android ${formatTargets(args, android)} - `); + `) } } diff --git a/types/bplist-parser.d.ts b/src/types/bplist-parser.d.ts similarity index 100% rename from types/bplist-parser.d.ts rename to src/types/bplist-parser.d.ts diff --git a/src/utils/cli.ts b/src/utils/cli.ts index e5c4521..7c3b7ed 100644 --- a/src/utils/cli.ts +++ b/src/utils/cli.ts @@ -1,35 +1,35 @@ export function getOptionValue( args: readonly string[], arg: string, -): string | undefined; +): string | undefined export function getOptionValue( args: readonly string[], arg: string, defaultValue: string, -): string; +): string export function getOptionValue( args: readonly string[], arg: string, defaultValue?: string, ): string | undefined { - const i = args.indexOf(arg); + const i = args.indexOf(arg) - if (i >= 0) { - return args[i + 1]; - } + if (i >= 0) + return args[i + 1] - return defaultValue; + return defaultValue } export function getOptionValues( args: readonly string[], arg: string, ): string[] { - const returnVal: string[] = []; + const returnVal: string[] = [] args.map((entry: string, idx: number) => { - if (entry === arg) { - returnVal.push(args[idx + 1]); - } - }); - return returnVal; + if (entry === arg) + returnVal.push(args[idx + 1]) + + return undefined + }) + return returnVal } diff --git a/src/utils/fn.ts b/src/utils/fn.ts index b33a8f2..c2a40f6 100644 --- a/src/utils/fn.ts +++ b/src/utils/fn.ts @@ -1,15 +1,15 @@ export function once any>(fn: T): T { - let called = false; - let r: any; + let called = false + let r: any const wrapper: any = (...args: any[]): any => { if (!called) { - called = true; - r = fn(...args); + called = true + r = fn(...args) } - return r; - }; + return r + } - return wrapper; + return wrapper } diff --git a/src/utils/fs.ts b/src/utils/fs.ts index ce27c55..7761fe5 100644 --- a/src/utils/fs.ts +++ b/src/utils/fs.ts @@ -1,11 +1,10 @@ -import { statSafe } from '@ionic/utils-fs'; +import { statSafe } from '@ionic/utils-fs' export async function isDir(p: string): Promise { - const stats = await statSafe(p); + const stats = await statSafe(p) - if (stats?.isDirectory()) { - return true; - } + if (stats?.isDirectory()) + return true - return false; + return false } diff --git a/src/utils/ini.ts b/src/utils/ini.ts index 2307cda..d5cb1a2 100644 --- a/src/utils/ini.ts +++ b/src/utils/ini.ts @@ -1,38 +1,39 @@ -import { readFile, writeFile } from '@ionic/utils-fs'; -import * as Debug from 'debug'; -import * as util from 'util'; +import * as util from 'node:util' +import { readFile, writeFile } from '@ionic/utils-fs' +import Debug from 'debug' -const debug = Debug('native-run:android:utils:ini'); +const debug = Debug('native-run:android:utils:ini') -export type INIGuard = (o: any) => o is T; +export type INIGuard = (o: any) => o is T export async function readINI( p: string, guard: INIGuard = (o: any): o is T => true, ): Promise { - const ini = await import('ini'); + const ini = await import('ini') try { - const contents = await readFile(p, { encoding: 'utf8' }); - const config = ini.decode(contents); + const contents = await readFile(p, { encoding: 'utf8' }) + const config = ini.decode(contents) if (!guard(config)) { throw new Error( - `Invalid ini configuration file: ${p}\n` + - `The following guard was used: ${guard.toString()}\n` + - `INI config parsed as: ${util.inspect(config)}`, - ); + `Invalid ini configuration file: ${p}\n` + + `The following guard was used: ${guard.toString()}\n` + + `INI config parsed as: ${util.inspect(config)}`, + ) } - return { __filename: p, ...(config as any) }; - } catch (e) { - debug(e); + return { __filename: p, ...(config as any) } + } + catch (e) { + debug(e) } } export async function writeINI(p: string, o: T): Promise { - const ini = await import('ini'); - const contents = ini.encode(o); + const ini = await import('ini') + const contents = ini.encode(o) - await writeFile(p, contents, { encoding: 'utf8' }); + await writeFile(p, contents, { encoding: 'utf8' }) } diff --git a/src/utils/json.ts b/src/utils/json.ts index 93c702a..8fb9073 100644 --- a/src/utils/json.ts +++ b/src/utils/json.ts @@ -3,5 +3,5 @@ export function stringify(obj: any): string { obj, (k, v) => (v instanceof RegExp ? v.toString() : v), '\t', - ); + ) } diff --git a/src/utils/list.ts b/src/utils/list.ts index 9ecdca6..8e9357d 100644 --- a/src/utils/list.ts +++ b/src/utils/list.ts @@ -1,91 +1,90 @@ -import { columnar, indent } from '@ionic/utils-terminal'; +import { columnar, indent } from '@ionic/utils-terminal' -import type { Exception } from '../errors'; -import { CLIException, ERR_BAD_INPUT, serializeError } from '../errors'; +import type { Exception } from '../errors' +import { CLIException, ERR_BAD_INPUT, serializeError } from '../errors' -import { stringify } from './json'; +import { stringify } from './json' export interface Targets { - readonly devices: readonly Target[]; - readonly virtualDevices: readonly Target[]; - readonly errors: readonly Exception[]; + readonly devices: readonly Target[] + readonly virtualDevices: readonly Target[] + readonly errors: readonly Exception[] } export interface Target { - readonly platform: 'android' | 'ios'; - readonly model?: string; - readonly name?: string; - readonly sdkVersion: string; - readonly id: string; + readonly platform: 'android' | 'ios' + readonly model?: string + readonly name?: string + readonly sdkVersion: string + readonly id: string } export function formatTargets( args: readonly string[], targets: Targets, ): string { - const { devices, virtualDevices, errors } = targets; + const { devices, virtualDevices, errors } = targets - const virtualOnly = args.includes('--virtual'); - const devicesOnly = args.includes('--device'); + const virtualOnly = args.includes('--virtual') + const devicesOnly = args.includes('--device') if (virtualOnly && devicesOnly) { throw new CLIException( 'Only one of --device or --virtual may be specified', ERR_BAD_INPUT, - ); + ) } if (args.includes('--json')) { - let result; - if (virtualOnly) { - result = { virtualDevices, errors }; - } else if (devicesOnly) { - result = { devices, errors }; - } else { - result = { devices, virtualDevices, errors }; - } - return stringify(result); + let result + if (virtualOnly) + result = { virtualDevices, errors } + else if (devicesOnly) + result = { devices, errors } + else + result = { devices, virtualDevices, errors } + + return stringify(result) } - let output = ''; + let output = '' - if (errors.length > 0) { - output += `Errors (!):\n\n${errors.map(e => ` ${serializeError(e)}`)}\n`; - } + if (errors.length > 0) + output += `Errors (!):\n\n${errors.map(e => ` ${serializeError(e)}`)}\n` if (!virtualOnly) { - output += printTargets('Connected Device', devices); - if (devicesOnly) { - return output; - } - output += '\n'; + output += printTargets('Connected Device', devices) + if (devicesOnly) + return output + + output += '\n' } - output += printTargets('Virtual Device', virtualDevices); - return output; + output += printTargets('Virtual Device', virtualDevices) + return output } function printTargets(name: string, targets: readonly Target[]) { - let output = `${name}s:\n\n`; - if (targets.length === 0) { - output += ` No ${name.toLowerCase()}s found\n`; - } else { - output += formatTargetTable(targets) + '\n'; - } - return output; + let output = `${name}s:\n\n` + if (targets.length === 0) + output += ` No ${name.toLowerCase()}s found\n` + else + output += `${formatTargetTable(targets)}\n` + + return output } function formatTargetTable(targets: readonly Target[]): string { - const spacer = indent(2); + const spacer = indent(2) return ( - spacer + - columnar(targets.map(targetToRow), { + spacer + + columnar(targets.map(targetToRow), { headers: ['Name', 'API', 'Target ID'], vsep: ' ', }) .split('\n') .join(`\n${spacer}`) - ); + ) } function targetToRow(target: Target): string[] { @@ -93,5 +92,5 @@ function targetToRow(target: Target): string[] { target.name ?? target.model ?? target.id ?? '?', `${target.platform === 'ios' ? 'iOS' : 'API'} ${target.sdkVersion}`, target.id ?? '?', - ]; + ] } diff --git a/src/utils/log.ts b/src/utils/log.ts index c93de17..f4a7f6b 100644 --- a/src/utils/log.ts +++ b/src/utils/log.ts @@ -1,9 +1,8 @@ -import { stringify } from './json'; +import { stringify } from './json' export function log(message: string): void { - if (process.argv.includes('--json')) { - message = stringify({ message }); - } + if (process.argv.includes('--json')) + message = stringify({ message }) - process.stdout.write(message); + process.stdout.write(message) } diff --git a/src/utils/object.ts b/src/utils/object.ts index 0ef07b1..565d78f 100644 --- a/src/utils/object.ts +++ b/src/utils/object.ts @@ -1,15 +1,13 @@ export function sort(obj: T): T { - const entries = [...Object.entries(obj)]; + const entries = [...Object.entries(obj)] - entries.sort(([k1], [k2]) => k1.localeCompare(k2)); + entries.sort(([k1], [k2]) => k1.localeCompare(k2)) - for (const [key] of entries) { - delete obj[key]; - } + for (const [key] of entries) + delete obj[key] - for (const [key, value] of entries) { - (obj as any)[key] = value; - } + for (const [key, value] of entries) + (obj as any)[key] = value - return obj; + return obj } diff --git a/src/utils/process.ts b/src/utils/process.ts index fe60afc..52cf056 100644 --- a/src/utils/process.ts +++ b/src/utils/process.ts @@ -1,21 +1,21 @@ -import * as cp from 'child_process'; -import * as Debug from 'debug'; -import * as util from 'util'; +import * as cp from 'node:child_process' +import * as util from 'node:util' +import Debug from 'debug' -import { once } from './fn'; +import { once } from './fn' -const debug = Debug('native-run:utils:process'); +const debug = Debug('native-run:utils:process') -export const exec = util.promisify(cp.exec); -export const execFile = util.promisify(cp.execFile); -export const wait = util.promisify(setTimeout); +export const exec = util.promisify(cp.exec) +export const execFile = util.promisify(cp.execFile) +export const wait = util.promisify(setTimeout) -export type ExitQueueFn = () => Promise; +export type ExitQueueFn = () => Promise -const exitQueue: ExitQueueFn[] = []; +const exitQueue: ExitQueueFn[] = [] export function onBeforeExit(fn: ExitQueueFn): void { - exitQueue.push(fn); + exitQueue.push(fn) } const BEFORE_EXIT_SIGNALS: NodeJS.Signals[] = [ @@ -23,32 +23,32 @@ const BEFORE_EXIT_SIGNALS: NodeJS.Signals[] = [ 'SIGTERM', 'SIGHUP', 'SIGBREAK', -]; +] const beforeExitHandlerWrapper = (signal: NodeJS.Signals) => once(async () => { - debug('onBeforeExit handler: %s received', signal); + debug('onBeforeExit handler: %s received', signal) debug( 'onBeforeExit handler: running %s queued functions', exitQueue.length, - ); + ) for (const [i, fn] of exitQueue.entries()) { try { - await fn(); - } catch (e) { - debug('Error from function %d in exit queue: %O', i, e); + await fn() + } + catch (e) { + debug('Error from function %d in exit queue: %O', i, e) } } debug( 'onBeforeExit handler: exiting (exit code %s)', process.exitCode ? process.exitCode : 0, - ); + ) - process.exit(); - }); + process.exit() + }) -for (const signal of BEFORE_EXIT_SIGNALS) { - process.on(signal, beforeExitHandlerWrapper(signal)); -} +for (const signal of BEFORE_EXIT_SIGNALS) + process.on(signal, beforeExitHandlerWrapper(signal)) diff --git a/src/utils/unzip.ts b/src/utils/unzip.ts index b2919f0..e4d5194 100644 --- a/src/utils/unzip.ts +++ b/src/utils/unzip.ts @@ -1,37 +1,36 @@ -import type { Readable } from 'stream'; -import { promisify } from 'util'; -import type { Entry, ZipFile, ZipFileOptions } from 'yauzl'; +import type { Readable } from 'node:stream' +import { promisify } from 'node:util' +import type { Entry, ZipFile, ZipFileOptions } from 'yauzl' // Specify which of possible overloads is being promisified type YauzlOpenReadStream = ( entry: Entry, options?: ZipFileOptions, callback?: (err: Error, stream: Readable) => void, -) => void; +) => void type UnzipOnEntry = ( entry: Entry, zipfile: ZipFile, openReadStream: (arg1: Entry, arg2?: ZipFileOptions) => Promise, -) => void; +) => void export async function unzip(srcPath: string, onEntry: UnzipOnEntry) { - const yauzl = await import('yauzl'); + const yauzl = await import('yauzl') return new Promise((resolve, reject) => { yauzl.open(srcPath, { lazyEntries: true }, (err, zipfile) => { - if (!zipfile || err) { - return reject(err); - } + if (!zipfile || err) + return reject(err) const openReadStream = promisify( zipfile.openReadStream.bind(zipfile) as YauzlOpenReadStream, - ); - zipfile.once('error', reject); + ) + zipfile.once('error', reject) // resolve when either one happens - zipfile.once('close', resolve); // fd of zip closed - zipfile.once('end', resolve); // last entry read - zipfile.on('entry', entry => onEntry(entry, zipfile, openReadStream)); - zipfile.readEntry(); - }); - }); + zipfile.once('close', resolve) // fd of zip closed + zipfile.once('end', resolve) // last entry read + zipfile.on('entry', entry => onEntry(entry, zipfile, openReadStream)) + zipfile.readEntry() + }) + }) } diff --git a/src/android/utils/__tests__/adb.ts b/test/android/utils/adb.ts similarity index 77% rename from src/android/utils/__tests__/adb.ts rename to test/android/utils/adb.ts index 663160c..0003b08 100644 --- a/src/android/utils/__tests__/adb.ts +++ b/test/android/utils/adb.ts @@ -1,21 +1,21 @@ -import * as os from 'os'; +import * as os from 'node:os' +import { beforeEach, describe, expect, it, vi } from 'vitest' -import type * as adb from '../adb'; +import * as adb from 'native-run/android/utils/adb' describe('android/utils/adb', () => { describe('parseAdbDevices', () => { - let adbUtils: typeof adb; + let adbUtils: typeof adb beforeEach(async () => { - jest.resetModules(); - adbUtils = await import('../adb'); - }); + vi.resetModules() + }) it('should parse emulator-5554 device', async () => { const output = ` List of devices attached -emulator-5554 device product:sdk_gphone_x86 model:Android_SDK_built_for_x86 device:generic_x86 transport_id:88\n\n`; - const devices = adbUtils.parseAdbDevices(output); +emulator-5554 device product:sdk_gphone_x86 model:Android_SDK_built_for_x86 device:generic_x86 transport_id:88\n\n` + const devices = adb.parseAdbDevices(output) expect(devices).toEqual([ { @@ -34,14 +34,14 @@ emulator-5554 device product:sdk_gphone_x86 model:Android_SDK_built_for transport_id: '88', }, }, - ]); - }); + ]) + }) it('should parse hardware device (LGUS996e5ef677)', async () => { const output = ` List of devices attached -LGUS996e5ef677 device usb:341835776X product:elsa_nao_us model:LG_US996 device:elsa transport_id:85\n\n`; - const devices = adbUtils.parseAdbDevices(output); +LGUS996e5ef677 device usb:341835776X product:elsa_nao_us model:LG_US996 device:elsa transport_id:85\n\n` + const devices = adbUtils.parseAdbDevices(output) expect(devices).toEqual([ { @@ -61,14 +61,14 @@ LGUS996e5ef677 device usb:341835776X product:elsa_nao_us model:LG_US996 transport_id: '85', }, }, - ]); - }); + ]) + }) it('should parse hardware device (0a388e93)', async () => { const output = ` List of devices attached -0a388e93 device usb:1-1 product:razor model:Nexus_7 device:flo\n\n`; - const devices = adbUtils.parseAdbDevices(output); +0a388e93 device usb:1-1 product:razor model:Nexus_7 device:flo\n\n` + const devices = adbUtils.parseAdbDevices(output) expect(devices).toEqual([ { @@ -87,14 +87,14 @@ List of devices attached device: 'flo', }, }, - ]); - }); + ]) + }) it('should parse hardware device over tcpip (192.168.0.3:5555)', async () => { const output = ` List of devices attached -192.168.0.3:5555 device product:mido model:Redmi_Note_4 device:mido transport_id:1\n\n`; - const devices = adbUtils.parseAdbDevices(output); +192.168.0.3:5555 device product:mido model:Redmi_Note_4 device:mido transport_id:1\n\n` + const devices = adbUtils.parseAdbDevices(output) expect(devices).toEqual([ { @@ -113,14 +113,14 @@ List of devices attached transport_id: '1', }, }, - ]); - }); + ]) + }) it('should parse hardware device from line without usb (98897a474748594558)', async () => { const output = ` List of devices attached -98897a474748594558 device product:dreamqltesq model:SM_G950U device:dreamqltesq transport_id:2\n\n`; - const devices = adbUtils.parseAdbDevices(output); +98897a474748594558 device product:dreamqltesq model:SM_G950U device:dreamqltesq transport_id:2\n\n` + const devices = adbUtils.parseAdbDevices(output) expect(devices).toEqual([ { @@ -139,22 +139,18 @@ List of devices attached transport_id: '2', }, }, - ]); - }); + ]) + }) describe('windows', () => { - let adbUtils: typeof adb; - beforeEach(async () => { - jest.resetModules(); - jest.mock('os', () => ({ ...os, EOL: '\r\n' })); - - adbUtils = await import('../adb'); - }); + vi.resetModules() + vi.mock('os', () => ({ ...os, EOL: '\r\n' })) + }) it('should parse hardware device (MWS0216B24001482)', async () => { - const output = `\r\nList of devices attached\r\nMWS0216B24001482 offline transport_id:3\r\n\r\n`; - const devices = adbUtils.parseAdbDevices(output); + const output = '\r\nList of devices attached\r\nMWS0216B24001482 offline transport_id:3\r\n\r\n' + const devices = adb.parseAdbDevices(output) expect(devices).toEqual([ { @@ -170,8 +166,8 @@ List of devices attached transport_id: '3', }, }, - ]); - }); - }); - }); -}); + ]) + }) + }) + }) +}) diff --git a/src/android/utils/__tests__/avd.ts b/test/android/utils/avd.ts similarity index 66% rename from src/android/utils/__tests__/avd.ts rename to test/android/utils/avd.ts index 7c9a9ab..ac59e25 100644 --- a/src/android/utils/__tests__/avd.ts +++ b/test/android/utils/avd.ts @@ -1,7 +1,8 @@ -import * as path from 'path'; +import path from 'node:path' -import * as iniUtils from '../../../utils/ini'; -import * as avdUtils from '../avd'; +import * as avdUtils from 'native-run/android/utils/avd' +import * as iniUtils from 'native-run/utils/ini' +import { describe, expect, it } from 'vitest' describe('android/utils/avd', () => { describe('getAVDFromINI', () => { @@ -9,9 +10,9 @@ describe('android/utils/avd', () => { const inipath = path.resolve( __dirname, './fixtures/avd/Pixel_2_API_28.ini', - ); - const ini: any = await iniUtils.readINI(inipath); - ini.path = path.resolve(__dirname, './fixtures/avd/Pixel_2_API_28.avd'); // patch path + ) + const ini: any = await iniUtils.readINI(inipath) + ini.path = path.resolve(__dirname, './fixtures/avd/Pixel_2_API_28.avd') // patch path const expected = { id: 'Pixel_2_API_28', @@ -21,22 +22,22 @@ describe('android/utils/avd', () => { screenDPI: 420, screenWidth: 1080, screenHeight: 1920, - }; + } - const avd = await avdUtils.getAVDFromINI(inipath, ini); - expect(avd).toEqual(expected); - }); + const avd = await avdUtils.getAVDFromINI(inipath, ini) + expect(avd).toEqual(expected) + }) it('should properly parse Pixel_2_XL_API_28', async () => { const inipath = path.resolve( __dirname, './fixtures/avd/Pixel_2_XL_API_28.ini', - ); - const ini: any = await iniUtils.readINI(inipath); + ) + const ini: any = await iniUtils.readINI(inipath) ini.path = path.resolve( __dirname, './fixtures/avd/Pixel_2_XL_API_28.avd', - ); // patch path + ) // patch path const expected = { id: 'Pixel_2_XL_API_28', @@ -46,19 +47,19 @@ describe('android/utils/avd', () => { screenDPI: 560, screenWidth: 1440, screenHeight: 2880, - }; + } - const avd = await avdUtils.getAVDFromINI(inipath, ini); - expect(avd).toEqual(expected); - }); + const avd = await avdUtils.getAVDFromINI(inipath, ini) + expect(avd).toEqual(expected) + }) it('should properly parse Pixel_API_25', async () => { const inipath = path.resolve( __dirname, './fixtures/avd/Pixel_API_25.ini', - ); - const ini: any = await iniUtils.readINI(inipath); - ini.path = path.resolve(__dirname, './fixtures/avd/Pixel_API_25.avd'); // patch path + ) + const ini: any = await iniUtils.readINI(inipath) + ini.path = path.resolve(__dirname, './fixtures/avd/Pixel_API_25.avd') // patch path const expected = { id: 'Pixel_API_25', @@ -68,19 +69,19 @@ describe('android/utils/avd', () => { screenDPI: 480, screenWidth: 1080, screenHeight: 1920, - }; + } - const avd = await avdUtils.getAVDFromINI(inipath, ini); - expect(avd).toEqual(expected); - }); + const avd = await avdUtils.getAVDFromINI(inipath, ini) + expect(avd).toEqual(expected) + }) it('should properly parse Nexus_5X_API_24', async () => { const inipath = path.resolve( __dirname, './fixtures/avd/Nexus_5X_API_24.ini', - ); - const ini: any = await iniUtils.readINI(inipath); - ini.path = path.resolve(__dirname, './fixtures/avd/Nexus_5X_API_24.avd'); // patch path + ) + const ini: any = await iniUtils.readINI(inipath) + ini.path = path.resolve(__dirname, './fixtures/avd/Nexus_5X_API_24.avd') // patch path const expected = { id: 'Nexus_5X_API_24', @@ -90,19 +91,19 @@ describe('android/utils/avd', () => { screenDPI: 420, screenWidth: 1080, screenHeight: 1920, - }; + } - const avd = await avdUtils.getAVDFromINI(inipath, ini); - expect(avd).toEqual(expected); - }); + const avd = await avdUtils.getAVDFromINI(inipath, ini) + expect(avd).toEqual(expected) + }) it('should properly parse avdmanager_1', async () => { const inipath = path.resolve( __dirname, './fixtures/avd/avdmanager_1.ini', - ); - const ini: any = await iniUtils.readINI(inipath); - ini.path = path.resolve(__dirname, './fixtures/avd/avdmanager_1.avd'); // patch path + ) + const ini: any = await iniUtils.readINI(inipath) + ini.path = path.resolve(__dirname, './fixtures/avd/avdmanager_1.avd') // patch path const expected = { id: 'avdmanager_1', @@ -112,10 +113,10 @@ describe('android/utils/avd', () => { screenDPI: null, screenWidth: null, screenHeight: null, - }; + } - const avd = await avdUtils.getAVDFromINI(inipath, ini); - expect(avd).toEqual(expected); - }); - }); -}); + const avd = await avdUtils.getAVDFromINI(inipath, ini) + expect(avd).toEqual(expected) + }) + }) +}) diff --git a/src/android/utils/__tests__/emulator.ts b/test/android/utils/emulator.ts similarity index 53% rename from src/android/utils/__tests__/emulator.ts rename to test/android/utils/emulator.ts index 0c7506a..739cea2 100644 --- a/src/android/utils/__tests__/emulator.ts +++ b/test/android/utils/emulator.ts @@ -1,36 +1,37 @@ -import { parseAndroidConsoleResponse } from '../emulator'; +import { parseAndroidConsoleResponse } from 'native-run/android/utils/emulator' +import { describe, expect, it } from 'vitest' const authRequiredOutput = `Android Console: Authentication required Android Console: type 'auth ' to authenticate Android Console: you can find your in '/Users/ionic/.emulator_console_auth_token' OK -`; +` describe('android/utils/emulator', () => { describe('parseAndroidConsoleResponse', () => { it('should not parse an event from whitespace', () => { for (const output of ['', '\n', ' \n']) { - const event = parseAndroidConsoleResponse(output); - expect(event).not.toBeDefined(); + const event = parseAndroidConsoleResponse(output) + expect(event).not.toBeDefined() } - }); + }) it('should not parse response from output until OK', () => { - const lines = authRequiredOutput.split('\n').slice(0, -2); + const lines = authRequiredOutput.split('\n').slice(0, -2) for (let i = 0; i < lines.length; i++) { - const output = lines.slice(0, i).join('\n'); - const event = parseAndroidConsoleResponse(output); - expect(event).not.toBeDefined(); + const output = lines.slice(0, i).join('\n') + const event = parseAndroidConsoleResponse(output) + expect(event).not.toBeDefined() } - }); + }) it('should parse response from output', () => { - const expected = - authRequiredOutput.split('\n').slice(0, -2).join('\n') + '\n'; - const event = parseAndroidConsoleResponse(authRequiredOutput); - expect(event).toBe(expected); - }); - }); -}); + const expected + = `${authRequiredOutput.split('\n').slice(0, -2).join('\n')}\n` + const event = parseAndroidConsoleResponse(authRequiredOutput) + expect(event).toBe(expected) + }) + }) +}) diff --git a/src/android/utils/__tests__/fixtures/avd/Nexus_5X_API_24.avd/config.ini b/test/android/utils/fixtures/avd/Nexus_5X_API_24.avd/config.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Nexus_5X_API_24.avd/config.ini rename to test/android/utils/fixtures/avd/Nexus_5X_API_24.avd/config.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Nexus_5X_API_24.ini b/test/android/utils/fixtures/avd/Nexus_5X_API_24.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Nexus_5X_API_24.ini rename to test/android/utils/fixtures/avd/Nexus_5X_API_24.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_2_API_28.avd/config.ini b/test/android/utils/fixtures/avd/Pixel_2_API_28.avd/config.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_2_API_28.avd/config.ini rename to test/android/utils/fixtures/avd/Pixel_2_API_28.avd/config.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_2_API_28.ini b/test/android/utils/fixtures/avd/Pixel_2_API_28.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_2_API_28.ini rename to test/android/utils/fixtures/avd/Pixel_2_API_28.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_2_XL_API_28.avd/config.ini b/test/android/utils/fixtures/avd/Pixel_2_XL_API_28.avd/config.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_2_XL_API_28.avd/config.ini rename to test/android/utils/fixtures/avd/Pixel_2_XL_API_28.avd/config.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_2_XL_API_28.ini b/test/android/utils/fixtures/avd/Pixel_2_XL_API_28.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_2_XL_API_28.ini rename to test/android/utils/fixtures/avd/Pixel_2_XL_API_28.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_API_25.avd/config.ini b/test/android/utils/fixtures/avd/Pixel_API_25.avd/config.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_API_25.avd/config.ini rename to test/android/utils/fixtures/avd/Pixel_API_25.avd/config.ini diff --git a/src/android/utils/__tests__/fixtures/avd/Pixel_API_25.ini b/test/android/utils/fixtures/avd/Pixel_API_25.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/Pixel_API_25.ini rename to test/android/utils/fixtures/avd/Pixel_API_25.ini diff --git a/src/android/utils/__tests__/fixtures/avd/README.md b/test/android/utils/fixtures/avd/README.md similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/README.md rename to test/android/utils/fixtures/avd/README.md diff --git a/src/android/utils/__tests__/fixtures/avd/avdmanager_1.avd/config.ini b/test/android/utils/fixtures/avd/avdmanager_1.avd/config.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/avdmanager_1.avd/config.ini rename to test/android/utils/fixtures/avd/avdmanager_1.avd/config.ini diff --git a/src/android/utils/__tests__/fixtures/avd/avdmanager_1.ini b/test/android/utils/fixtures/avd/avdmanager_1.ini similarity index 100% rename from src/android/utils/__tests__/fixtures/avd/avdmanager_1.ini rename to test/android/utils/fixtures/avd/avdmanager_1.ini diff --git a/src/android/utils/sdk/__tests__/api.ts b/test/android/utils/sdk/api.ts similarity index 67% rename from src/android/utils/sdk/__tests__/api.ts rename to test/android/utils/sdk/api.ts index e549a25..4d0b583 100644 --- a/src/android/utils/sdk/__tests__/api.ts +++ b/test/android/utils/sdk/api.ts @@ -1,5 +1,6 @@ -import type { APISchemaPackage } from '../api'; -import { findPackageBySchema, findUnsatisfiedPackages } from '../api'; +import type { APISchemaPackage } from 'native-run/android/utils/sdk/api' +import { findPackageBySchema, findUnsatisfiedPackages } from 'native-run/android/utils/sdk/api' +import { describe, expect, it } from 'vitest' describe('android/utils/sdk/api', () => { const FooPackage = { @@ -7,79 +8,79 @@ describe('android/utils/sdk/api', () => { location: '/Users/me/Android/sdk/foo', name: 'Foo', version: '1', - }; + } const BarPackage = { path: 'bar', location: '/Users/me/Android/sdk/bar', name: 'Bar', version: '1.0.0', - }; + } const BarPackageInvalidVersion = { path: 'bar', location: '/Users/me/Android/sdk/bar', name: 'Bar', version: '2.0.0', - }; + } - const FooPackageSchema = { name: 'Foo', path: 'foo', version: '1' }; + const FooPackageSchema = { name: 'Foo', path: 'foo', version: '1' } const BarPackageSchema = { name: 'Bar', path: 'bar', version: /^1\.\d+\.\d+$/, - }; + } describe('findUnsatisfiedPackages', () => { const schemaPackages: APISchemaPackage[] = [ FooPackageSchema, BarPackageSchema, - ]; + ] it('should return all package schemas for empty packages', () => { - const result = findUnsatisfiedPackages([], schemaPackages); - expect(result).toEqual(schemaPackages); - }); + const result = findUnsatisfiedPackages([], schemaPackages) + expect(result).toEqual(schemaPackages) + }) it('should return unsatisfied packages for missing', () => { - const api = [FooPackage]; - const result = findUnsatisfiedPackages(api, schemaPackages); - expect(result).toEqual([BarPackageSchema]); - }); + const api = [FooPackage] + const result = findUnsatisfiedPackages(api, schemaPackages) + expect(result).toEqual([BarPackageSchema]) + }) it('should return unsatisfied packages for invalid version', () => { - const api = [FooPackage, BarPackageInvalidVersion]; - const result = findUnsatisfiedPackages(api, schemaPackages); - expect(result).toEqual([BarPackageSchema]); - }); + const api = [FooPackage, BarPackageInvalidVersion] + const result = findUnsatisfiedPackages(api, schemaPackages) + expect(result).toEqual([BarPackageSchema]) + }) it('should return empty array if everything is satisfied', () => { - const api = [FooPackage, BarPackage]; - const result = findUnsatisfiedPackages(api, schemaPackages); - expect(result).toEqual([]); - }); - }); + const api = [FooPackage, BarPackage] + const result = findUnsatisfiedPackages(api, schemaPackages) + expect(result).toEqual([]) + }) + }) describe('findPackageBySchema', () => { it('should not find package in empty api', () => { - const pkg = findPackageBySchema([], FooPackageSchema); - expect(pkg).toBeUndefined(); - }); + const pkg = findPackageBySchema([], FooPackageSchema) + expect(pkg).toBeUndefined() + }) it('should not find package for invalid version', () => { const pkg = findPackageBySchema( [FooPackage, BarPackageInvalidVersion], BarPackageSchema, - ); - expect(pkg).toBeUndefined(); - }); + ) + expect(pkg).toBeUndefined() + }) it('should find foo package by schema', () => { const pkg = findPackageBySchema( [FooPackage, BarPackage], FooPackageSchema, - ); - expect(pkg).toBe(FooPackage); - }); - }); -}); + ) + expect(pkg).toBe(FooPackage) + }) + }) +}) diff --git a/src/android/utils/sdk/__tests__/index.ts b/test/android/utils/sdk/index.ts similarity index 56% rename from src/android/utils/sdk/__tests__/index.ts rename to test/android/utils/sdk/index.ts index 973d04f..2103d10 100644 --- a/src/android/utils/sdk/__tests__/index.ts +++ b/test/android/utils/sdk/index.ts @@ -1,46 +1,46 @@ -import * as path from 'path'; +import * as path from 'node:path' -import type * as index from '../'; +import * as sdkUtils from 'native-run/android/utils/sdk' +import type { Mock } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' describe('android/utils/sdk', () => { - let sdkUtils: typeof index; - let mockIsDir: jest.Mock; - let mockHomedir: jest.Mock; - let originalPlatform: string; - let originalProcessEnv: NodeJS.ProcessEnv; + let mockIsDir: Mock + let mockHomedir: Mock + let originalPlatform: string + let originalProcessEnv: NodeJS.ProcessEnv beforeEach(() => { - mockIsDir = jest.fn(); - mockHomedir = jest.fn().mockReturnValue('/home/me'); - originalPlatform = process.platform; - originalProcessEnv = process.env; + mockIsDir = vi.fn() + mockHomedir = vi.fn().mockReturnValue('/home/me') + originalPlatform = process.platform + originalProcessEnv = process.env - jest.resetModules(); - jest.mock('path', () => path); - jest.mock('os', () => ({ homedir: mockHomedir })); - jest.mock('../../../../utils/fs', () => ({ isDir: mockIsDir })); - }); + vi.resetModules() + vi.mock('path', () => path) + vi.mock('os', () => ({ homedir: mockHomedir })) + vi.mock('native-run/android/utils/sdk', () => ({ isDir: mockIsDir })) + }) afterEach(() => { - Object.defineProperty(process, 'env', { value: originalProcessEnv }); - Object.defineProperty(process, 'platform', { value: originalPlatform }); - }); + Object.defineProperty(process, 'env', { value: originalProcessEnv }) + Object.defineProperty(process, 'platform', { value: originalPlatform }) + }) describe('SDK_DIRECTORIES', () => { describe('windows', () => { beforeEach(() => { - jest.mock('path', () => path.win32); - mockHomedir = jest.fn().mockReturnValue('C:\\Users\\me'); - jest.mock('os', () => ({ homedir: mockHomedir })); - }); + vi.mock('path', () => path.win32) + mockHomedir = vi.fn().mockReturnValue('C:\\Users\\me') + vi.mock('os', () => ({ homedir: mockHomedir })) + }) it('should default to windows 10 local app data directory', async () => { - Object.defineProperty(process, 'env', { value: {} }); - sdkUtils = await import('../'); + Object.defineProperty(process, 'env', { value: {} }) expect(sdkUtils.SDK_DIRECTORIES.get('win32')).toEqual([ path.win32.join('C:\\Users\\me\\AppData\\Local\\Android\\Sdk'), - ]); - }); + ]) + }) it('should use LOCALAPPDATA environment variable if present', async () => { Object.defineProperty(process, 'env', { @@ -52,78 +52,73 @@ describe('android/utils/sdk', () => { 'Application Data', ), }, - }); - sdkUtils = await import('../'); + }) expect(sdkUtils.SDK_DIRECTORIES.get('win32')).toEqual([ path.win32.join( 'C:\\Documents and Settings\\me\\Application Data\\Android\\Sdk', ), - ]); - }); - }); - }); + ]) + }) + }) + }) describe('resolveSDKRoot', () => { - beforeEach(async () => { - sdkUtils = await import('../'); - }); - it('should resolve with ANDROID_HOME if in environment', async () => { - mockIsDir.mockResolvedValueOnce(true); + mockIsDir.mockResolvedValueOnce(true) Object.defineProperty(process, 'env', { value: { ANDROID_HOME: '/some/dir', ANDROID_SDK_ROOT: '/some/other/dir', }, - }); - await expect(sdkUtils.resolveSDKRoot()).resolves.toEqual('/some/dir'); - expect(mockIsDir).toHaveBeenCalledTimes(1); - expect(mockIsDir).toHaveBeenCalledWith('/some/dir'); - }); + }) + await expect(sdkUtils.resolveSDKRoot()).resolves.toEqual('/some/dir') + expect(mockIsDir).toHaveBeenCalledTimes(1) + expect(mockIsDir).toHaveBeenCalledWith('/some/dir') + }) it('should resolve with ANDROID_SDK_ROOT if in environment', async () => { - mockIsDir.mockResolvedValueOnce(true); + mockIsDir.mockResolvedValueOnce(true) Object.defineProperty(process, 'env', { value: { ANDROID_SDK_ROOT: '/some/other/dir' }, - }); + }) await expect(sdkUtils.resolveSDKRoot()).resolves.toEqual( '/some/other/dir', - ); - expect(mockIsDir).toHaveBeenCalledTimes(1); - expect(mockIsDir).toHaveBeenCalledWith('/some/other/dir'); - }); + ) + expect(mockIsDir).toHaveBeenCalledTimes(1) + expect(mockIsDir).toHaveBeenCalledWith('/some/other/dir') + }) it('should resolve with default value for empty environment on linux', async () => { - mockIsDir.mockResolvedValueOnce(true); - Object.defineProperty(process, 'env', { value: {} }); - Object.defineProperty(process, 'platform', { value: 'linux' }); + mockIsDir.mockResolvedValueOnce(true) + Object.defineProperty(process, 'env', { value: {} }) + Object.defineProperty(process, 'platform', { value: 'linux' }) await expect(sdkUtils.resolveSDKRoot()).resolves.toEqual( '/home/me/Android/sdk', - ); - expect(mockIsDir).toHaveBeenCalledTimes(1); - expect(mockIsDir).toHaveBeenCalledWith('/home/me/Android/sdk'); - }); + ) + expect(mockIsDir).toHaveBeenCalledTimes(1) + expect(mockIsDir).toHaveBeenCalledWith('/home/me/Android/sdk') + }) it('should resolve with default value for empty environment on darwin', async () => { - mockIsDir.mockResolvedValueOnce(true); - Object.defineProperty(process, 'env', { value: {} }); - Object.defineProperty(process, 'platform', { value: 'darwin' }); + mockIsDir.mockResolvedValueOnce(true) + Object.defineProperty(process, 'env', { value: {} }) + Object.defineProperty(process, 'platform', { value: 'darwin' }) await expect(sdkUtils.resolveSDKRoot()).resolves.toEqual( '/home/me/Library/Android/sdk', - ); - expect(mockIsDir).toHaveBeenCalledTimes(1); - expect(mockIsDir).toHaveBeenCalledWith('/home/me/Library/Android/sdk'); - }); + ) + expect(mockIsDir).toHaveBeenCalledTimes(1) + expect(mockIsDir).toHaveBeenCalledWith('/home/me/Library/Android/sdk') + }) it('should reject if no valid directories are found', async () => { - mockIsDir.mockResolvedValueOnce(false); - Object.defineProperty(process, 'env', { value: {} }); - Object.defineProperty(process, 'platform', { value: 'darwin' }); + mockIsDir.mockResolvedValueOnce(false) + Object.defineProperty(process, 'env', { value: {} }) + Object.defineProperty(process, 'platform', { value: 'darwin' }) await expect(sdkUtils.resolveSDKRoot()).rejects.toThrowError( 'No valid Android SDK root found.', - ); - expect(mockIsDir).toHaveBeenCalledTimes(1); - expect(mockIsDir).toHaveBeenCalledWith('/home/me/Library/Android/sdk'); - }); - }); -}); + ) + expect(mockIsDir).toHaveBeenCalledTimes(1) + expect(mockIsDir).toHaveBeenCalledWith('/home/me/Library/Android/sdk') + }) + }) +}) diff --git a/test/utils/fn.test.ts b/test/utils/fn.test.ts new file mode 100644 index 0000000..0bd8674 --- /dev/null +++ b/test/utils/fn.test.ts @@ -0,0 +1,31 @@ +import { once } from 'native-run/utils/fn' +import { describe, expect, it, vi } from 'vitest' + +describe('utils/fn', () => { + describe('once', () => { + it('should call function once despite multiple calls', () => { + const mock = vi.fn() + const fn = once(mock) + fn() + fn() + expect(mock).toHaveBeenCalledTimes(1) + }) + + it('should call function with original parameters', () => { + const mock = vi.fn() + const fn = once(mock) + fn(5, 'foobar', { foo: 'bar' }) + expect(mock).toHaveBeenCalledTimes(1) + expect(mock).toHaveBeenCalledWith(5, 'foobar', { foo: 'bar' }) + }) + + it('should return the exact same object', () => { + const expected = {} + const mock = vi.fn(() => expected) + const fn = once(mock) + const r = fn() + expect(mock).toHaveBeenCalledTimes(1) + expect(r).toBe(expected) + }) + }) +}) diff --git a/test/utils/object.test.ts b/test/utils/object.test.ts new file mode 100644 index 0000000..7845731 --- /dev/null +++ b/test/utils/object.test.ts @@ -0,0 +1,20 @@ +import { sort } from 'native-run/utils/object' +import { describe, expect, it } from 'vitest' + +describe('utils/object', () => { + describe('sort', () => { + it('should return the same object', () => { + const obj = { c: 3, b: 2, a: 1 } + const result = sort(obj) + expect(result).toBe(obj) + expect(obj).toEqual({ c: 3, b: 2, a: 1 }) + }) + + it('should sort the keys', () => { + const obj = { c: 3, b: 2, a: 1 } + expect(Object.keys(obj)).toEqual(['c', 'b', 'a']) + sort(obj) + expect(Object.keys(obj)).toEqual(['a', 'b', 'c']) + }) + }) +}) diff --git a/tsconfig.json b/tsconfig.json index 6a35f5a..8ea61bc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,26 +1,23 @@ { - "compilerOptions": { - "allowUnreachableCode": false, - "importHelpers": true, - "module": "commonjs", - "moduleResolution": "node", - "resolveJsonModule": true, - "noFallthroughCasesInSwitch": true, - "noUnusedLocals": true, - "outDir": "./dist", - "pretty": true, - "strict": true, - "target": "es2019", - "lib": [ - "es2019" - ] - }, - "include": [ - "src/**/*", - "types/**/*" - ], - "exclude": [ - "node_modules", - "src/**/__tests__/*.ts" - ] -} + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node 14", + "compilerOptions": { + "baseUrl": ".", + "lib": [ + "es2020" + ], + "module": "commonjs", + "target": "es2020", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "paths": { + "native-run/*": [ + "src/*" + ] + } + } +} \ No newline at end of file diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..5ba56a5 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,17 @@ +import type { Options } from 'tsup' + +import pkg from './package.json' +const external = [ + ...Object.keys(pkg.peerDependencies || {}), +] + +export default { + entryPoints: ['src/index.ts', 'src/android/index.ts', 'src/ios/index.ts', 'src/utils/*.ts'], + outDir: 'dist', + target: 'node16', + format: ['esm', 'cjs'], + clean: true, + dts: true, + minify: true, + external, +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..b70709d --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,29 @@ +import path from 'node:path' +import { defineConfig } from 'vitest/config' + +const alias = (p: string) => path.resolve(__dirname, p) + +export default defineConfig({ + optimizeDeps: { + entries: [], + }, + test: { + coverage: { + provider: 'c8', // or 'c8', + reporter: ['text', 'json-summary', 'json', 'html'], + }, + exclude: [ + '**/node_modules/**', + '**/dist/**', + './test/**/fixtures/**', + ], + include: [ + './test/**', + ], + }, + resolve: { + alias: { + 'native-run': alias('./src/'), + }, + }, +})