diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 0000000..114ecf0 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,22 @@ +{ + "projectName": "html-to-latex", + "projectOwner": "jdalrymple", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 25, + "commit": false, + "wrapperTemplate": "

<%= bodyContent %>

", + "commitConvention": "angular", + "contributorTemplate": "\">&h=<%= options.imageSize %>&w=<%= options.imageSize %>&fit=cover&mask=circle&maxage=7d\" alt=\"<%= contributor.name %>\"/>", + "contributors": [ + { + "login": "jdalrymple", + "name": "Justin Dalrymple", + "avatar_url": "https://avatars3.githubusercontent.com/u/3743662?v=4", + "profile": "https://github.com/jdalrymple", + "contributions": ["code", "review", "maintenance", "bug", "ideas", "doc", "test", "infra"] + } + ], + "contributorsPerLine": 26 +} diff --git a/.autorc.yml b/.autorc.yml new file mode 100644 index 0000000..bdabfa1 --- /dev/null +++ b/.autorc.yml @@ -0,0 +1,63 @@ +noVersionPrefix: true + +plugins: + - npm + - released + - first-time-contributor + - all-contributors + +prereleaseBranches: + - next + +noDefaultLabels: true + +labels: + - name: breaking + changelogTitle: 💥 Breaking Change + description: Changes are not backwards compatible + releaseType: major + + - name: type:feature + changelogTitle: ✨ Feature + description: Changes add a new feature + releaseType: minor + + - name: type:bug + changelogTitle: 🐛 Bug Fix + description: Changes fix a minor bug + releaseType: minor + + - name: type:hot fix + changelogTitle: 🚑 Hot Fix + description: Changes fix a critical bug + releaseType: minor + + - name: type:technical debt + changelogTitle: 🔨 Technical Debt + description: Changes only affect the internal code, improving performance/quality + releaseType: patch + + - name: type:security + changelogTitle: 🔒 Security + description: Changes improve the code security + releaseType: patch + + - name: type:dependencies + changelogTitle: ↕️ Dependencies + description: Changes upgrade or remove dependencies + releaseType: patch + + - name: type:types + changelogTitle: 🗃️ Typescript Definitions + description: Changes only affect typescript definitions + releaseType: patch + + - name: type:testing + changelogTitle: 🚨 Tests + description: Changes affect test code + releaseType: none + + - name: type:documentation + changelogTitle: 📚 Documentation + description: Changes only affect the documentation + releaseType: none diff --git a/.codeclimate.yml b/.codeclimate.yml index d44f3e8..da49527 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,19 +1,4 @@ -engines: - shellcheck: - enabled: true - duplication: - enabled: true - config: - languages: - javascript: - mass_threshold: 70 - count_threshold: 3 +version: '2' -ratings: - paths: - - '**.js' - -exclude_paths: - - node_modules - - coverage - - dist +exclude_patterns: + - '**/test/' diff --git a/.eslintrc.yml b/.eslintrc.yml index cb5c98d..e2d4ef0 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,29 +1,53 @@ env: node: true - jest/globals: true extends: - airbnb-base + - plugin:@typescript-eslint/recommended-requiring-type-checking - plugin:prettier/recommended - - plugin:jest/recommended + +parser: '@typescript-eslint/parser' + +parserOptions: + project: + - './tsconfig.json' ignorePatterns: - node_modules/ - dist/ - - '**/rollup.config.js' plugins: + - '@typescript-eslint' + - prettier - import rules: + no-console: + - error + - allow: + - debug + + no-use-before-define: + - error + - functions: false + classes: false + import/prefer-default-export: off - import/extensions: + + sort-imports: - error - - never - - json: always + - ignoreCase: false + ignoreDeclarationSort: true + ignoreMemberSort: false + memberSyntaxSortOrder: + - none + - all + - multiple + - single + allowSeparatedGroups: true settings: import/resolver: + typescript: node: - extensions: - - .js + extensions: ['.mjs', '.cjs', '.js', '.jsx', '.json', '.mts', '.cts', '.ts', '.tsx', '.d.ts'] diff --git a/.github/ISSUE_TEMPLATE/1-bug.md b/.github/ISSUE_TEMPLATE/1-bug.md new file mode 100644 index 0000000..65ee2ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug.md @@ -0,0 +1,37 @@ +--- +name: '🐞 Bug report' +labels: bug +about: Something is not working as it should +--- + +**Description** + +- Node.js version: +- Package version: +- OS & version: + + + +**Steps to reproduce** + + + +**Expected behaviour** + + + +**Actual behaviour** + + + +**Possible fixes** + + + +**Checklist** + +- [ ] I have checked that this is not a duplicate issue. +- [ ] I have read the documentation. diff --git a/.github/ISSUE_TEMPLATE/2-feature-proposal.md b/.github/ISSUE_TEMPLATE/2-feature-proposal.md new file mode 100644 index 0000000..45f0b10 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature-proposal.md @@ -0,0 +1,18 @@ +--- +name: '🚀 Feature request' +labels: feature +about: Suggest an idea +--- + +**Description** + + + +**Proposal** + + + +**Checklist** + +- [ ] I have checked that this is not a duplicate issue. +- [ ] I have read the documentation. diff --git a/.github/ISSUE_TEMPLATE/3-question.md b/.github/ISSUE_TEMPLATE/3-question.md new file mode 100644 index 0000000..78d8118 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-question.md @@ -0,0 +1,16 @@ +--- +name: '❓ Question' +labels: question +about: Something is unclear or needs to be discussed +--- + + + +**Description** + + + +**Checklist** + +- [ ] I have checked that this is not a duplicate issue. +- [ ] I have read the documentation. diff --git a/.github/ISSUE_TEMPLATE/4-technical-debt.md b/.github/ISSUE_TEMPLATE/4-technical-debt.md new file mode 100644 index 0000000..97f2855 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4-technical-debt.md @@ -0,0 +1,21 @@ +--- +name: '🚧 Technical Debt' +labels: 'technical debt' +about: Suggest an improvement to the codebase +--- + +**Description** + + + +**Possible solutions** + + + +**Checklist** + +- [ ] I have checked that this is not a duplicate issue. +- [ ] I have read the documentation. diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..57da4a3 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,32 @@ +name: 'Setup' + +runs: + using: 'composite' + steps: + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + shell: bash + run: pnpm install \ No newline at end of file diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml new file mode 100644 index 0000000..724d696 --- /dev/null +++ b/.github/workflows/pipeline.yml @@ -0,0 +1,122 @@ +name: Pipeline + +on: + workflow_dispatch: + push: + +jobs: + install: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + + build: + runs-on: ubuntu-latest + needs: [install] + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Build package + run: pnpm build + - name: Temporarily save build files + uses: actions/upload-artifact@v3 + with: + name: build-artifacts + path: dist + retention-days: 1 + + lint: + runs-on: ubuntu-latest + needs: [install] + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Lint + run: pnpm lint + + format: + runs-on: ubuntu-latest + needs: [install] + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Format + run: pnpm format + + test: + runs-on: ubuntu-latest + needs: [install] + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Run unit tests + run: pnpm test:unit + - uses: paambaati/codeclimate-action@v5 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + + release-dry-run: + runs-on: ubuntu-latest + if: github.ref != 'refs/heads/main' + needs: [lint, format, build, test] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + fetch-depth: 100 + - name: Fetch Git tags + shell: bash + run: git fetch --tags --force + - uses: ./.github/actions/setup + - name: Retrieve saved build files + uses: actions/download-artifact@v3 + with: + name: build-artifacts + path: dist + - name: Dry Run Deployment + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_USERNAME: ${{ github.actor }} + run: | + npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN + git config --global user.email "${GH_USERNAME}@users.noreply.github.com" + git config --global user.name "${GH_USERNAME}" + pnpm release --dry-run + + release: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'skip ci') + needs: [lint, format, build, test] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.GH_TOKEN }} + fetch-depth: 100 + - name: Fetch Git tags + shell: bash + run: git fetch --tags --force + - uses: ./.github/actions/setup + - name: Retrieve saved build files + uses: actions/download-artifact@v3 + with: + name: build-artifacts + path: dist + - name: Deploy + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_USERNAME: ${{ github.actor }} + run: | + npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN + git config --global user.email "${GH_USERNAME}@users.noreply.github.com" + git config --global user.name "${GH_USERNAME}" + pnpm release diff --git a/.github/workflows/pkgsize.yml b/.github/workflows/pkgsize.yml new file mode 100644 index 0000000..e937d39 --- /dev/null +++ b/.github/workflows/pkgsize.yml @@ -0,0 +1,19 @@ +name: Package Size + +on: + pull_request: + +jobs: + generate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - name: Package size report + uses: pkg-size/action@v1 + with: + build-command: pnpm build + display-size: uncompressed, gzip + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.gitignore b/.gitignore index 7133ef1..f72f912 100644 --- a/.gitignore +++ b/.gitignore @@ -1,55 +1,15 @@ - -# Created by https://www.gitignore.io/api/macos,windows,linux,node - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### macOS ### -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Node ### # Logs logs +reports *.log npm-debug.log* yarn-debug.log* yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids @@ -62,28 +22,23 @@ lib-cov # Coverage directory used by tools like istanbul coverage +*.lcov # nyc test coverage .nyc_output -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - # node-waf configuration .lock-wscript -# Compiled binary addons (http://nodejs.org/api/addons.html) +# Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ -# Typescript v1 declaration files -typings/ +# TypeScript cache +*.tsbuildinfo # Optional npm cache directory .npm @@ -97,38 +52,8 @@ typings/ # Output of 'npm pack' *.tgz -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# End of https://www.gitignore.io/api/macos,windows,linux,node - -package-lock.json -yarn.lock +# Build dist -*.pdf -*.aux \ No newline at end of file + +# Test artifacts +test-artifacts \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..6cfc9bf --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +.turbo +coverage +dist +package.json +yarn.lock +CHANGELOG.md diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 62efcc2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: ~> 1.0 - -language: node_js - -node_js: - - node - -jobs: - include: - - stage: lint - script: - - yarn lint - - - stage: build - script: - - yarn build - - - stage: test - script: - - yarn test && yarn codecov diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d79ca3c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at justin.s.dalrymple@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a1defcb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,92 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Process + +1. Ensure any install or build dependencies are removed before the end of the layer when doing a + build. +2. Update the README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/LICENSE b/LICENSE index 8e44342..528eaa5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Contributors +Copyright (c) 2024 Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 64c13c0..e3256cb 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,13 @@

HTML-to-Latex

-

Basic script to convert HTML source into Latex

- - Travis Pipeline Status + pipeline status + + Code Climate maintainability /> + + Auto - - Code Climate maintainability - - - CodeCov test coverage - - - Dependency Status - - - Dev Dependency Status - - Dependabot Badge - - Commitizen + + All Contributors Prettier @@ -29,273 +18,139 @@

-**[IN DEVELOPMENT]** - -## Install - -```bash -$ npm install html-to-latex -``` - -## Usage - -Converting html text: -```javascript -import { convertText } from 'html-to-latex'; - -const html = `

Styled Text

`; -const tex = await convertText(html); - -console.log(tex) -//\documentclass{article} -// -//\begin{document} -// -//Styled \textbf{Text} -// -//\end{document} -``` - -Converting html file: -```javascript -import { convertFile } from 'html-to-latex'; - -const html = 'filePath.html'; - -await convertFile(html); -``` - -### API - -#### convertText(htmlText, options?) - -Returns: `Promise` - -Converts the input htmlText to a valid latex string. - -##### htmlString - -Type: `string` - -##### options - -Type: `object` - -###### ignoreBreaks - -Type: `boolean` -Default: `true` -CLI Options: `-ib` or `--ignore-breaks` - -Instead of replacing `
` with //, ending the line, a simple space character is inserted instead. - -###### preferDollarInlineMath - -Type: `boolean` -Default: `false` -CLI Options: `-dm` or `--prefer-dollar-inline-math` - -Replace `\(` and `\)` with `$`. - -###### skipWrappingEquations - -Type: `boolean` -Default: `false` -CLI Options: `-swe` or `--skip-wrapping-equations` - -Is an equation is defined in a `p` tag without any other content besides that equation, it will automatically be wrapped in `\[` and `\]`. - -###### includeDocumentWrapper - -Type: `boolean` -Default: `false` -CLI Options: `-dw` or `--include-document-wrapper` - -Adds a latex document wrapper around the converted text. This is required to have a valid latex file: - -```latex -\documentclass{article} - -\begin{document} -%...converted text -\end{document} -``` - -###### documentClass - -Type: `string` -Default: `article` -CLI Options: `-dc` or `--document-class` - -If a document wrapper is added, the document class will be set. - -```latex -\documentclass{article} -%... -``` +> A basic library for converting HTML source into Latex. -###### includePackages +## Table of Contents -Type: `string[]` -Default: `[]`* -CLI Options: `-ip` or `--include-packages` +- [Usage](#usage) +- [API](#api) +- [FAQ](#faq) +- [Contributors](#contributors) +- [Changelog](./CHANGELOG.md) -If the document wrapper is added, a list of used packages will be set. +## Features -```latex -\documentclass{article} +- **Universal** - Works in all modern browsers, [Node.js](https://nodejs.org/), and [Deno](https://deno.land/) and supports CLI usage. +- **Tiny Size** - 12.5kb packed, 65.5kb unpacked. +- **Tested** - Greater than 98% test coverage. +- **Typed** - Out of the box TypeScript declarations. -\usepackage{packagename} +## Usage -\begin{document} -%...converted text -\end{document} + + + + + + + + + + + + + + + +
Browsers +Load html-to-latex directly from esm.sh + +```html + ``` -\*If nothing is specified, the list of includes packages will be inferred from the html: - - -| Tag | Added Package | -|--------|---------------| -| \cfrac | amsmath | -| \img | graphicx | -| \therefore | amssymb | - -###### title - -Type: `string` -Default: `undefined` -CLI Options: `-t` or `--title` - -If a document wrapper is added, the title will be set. +
Deno +Load html-to-latex directly from esm.sh -```latex -\documentclass{article} - -\title{Altered Carbon} - -\begin{document} -%...converted text -\end{document} +```ts +import { convertText, convertFile } from 'https://esm.sh/html-to-latex?dts'; ``` -###### author - -Type: `string` -Default: `undefined` -CLI Options: `-a` or `--author` +
Node 18+ -If a document wrapper is added, the author will be set. +Install with npm install html-to-latex, yarn add html-to-latex, or pnpm add html-to-latex -```latex -\documentclass{article} - -\author{Takashi Kovacs} - -\begin{document} -%...converted text -\end{document} +```js +import { convertText, convertFile } from 'html-to-latex'; ``` -###### includeDate - -Type: `boolean` -Default: `false` -CLI Options: `-d` or `--incude-date` +OR as a CLI, -If a document wrapper is added, the current date will be set. +Run with npx, yarn dlx or pnpm dlx -```latex -\documentclass{article} - -\date{\today} +```bash +html-to-latex [function name] positional_arg --opts_arg1 --opts_argN -\begin{document} -%...converted text -\end{document} +# A shorthand can also be used: +h2l [function name] positional_arg --opts_arg1 --opts_argN ``` -###### compilationDir - -Type: `string` -Default: `process.cwd` -CLI Options: `-cdr` or `--compilation-dir` - -If any images need to be downloaded for the latex compilation, they will be places in a 'images' subdirectory inside this directory. - -###### autoGenImageNames - -Type: `boolean` -Default: `true` -CLI Options: `-ain` or `--autogen-image-names` - -To avoid any weird file names, image files that are downloaded are automatically given a random Id with the extension of the original file. This can be turned off by passing a `false` value. - -###### imageWidth - -Type: `string` -Default: `undefined` -CLI Options: `-iw` or `--image-width` - -Allows you to set a image width. This would be in the form normally accepted by latex such as: `2cm` - -###### imageHeight - -Type: `string` -Default: `undefined` -CLI Options: `-ih` or `--image-height` - -Allows you to set a image height. This would be in the form normally accepted by latex such as: `2cm` - -###### keepImageAspectRatio - -Type: `boolean` -Default: `undefined` -CLI Options: `-kar` or `--keep-aspect-ratio` - -Allows you to maintain the aspect ratio of the image. This also requires either the image width property or image height property to be set. - -###### debug - -Type: `boolean` -Default: `false` -CLI Options: `--debug` - -Prints error messages when they occur such as when an image cannot be found at the given url. - - -#### convertFile(filepath, options?) -CLI: `available` (see options for cli option names) -Returns: `Promise` - -Converts the input file to a valid latex file. - -##### filepath - -Type: `string` -CLI Option: Positional, or `-ifp` - -Path of html file - -##### options - -Type: `object` - -All options included in .... and - -*includeDocumentWrapper option is defaulted to true for this function, as it would make more sense to do so* - -##### outputFilepath - -Type: `string` -Default: `filepath` (The input file path) -CLI Option: `-ofp` or `--output-file-path` - -The output filepath of the converted file. By default it will overwrite the input file. - -### CLI API -The same arguments are valid for the cli. The cli is exposed under html-to-latex executable and has the functions: `convert-file` and `convert-text`. Run `html-to-latex --help` for more information. - -## Improving output -### Ignoring br tags -Instead designate new sections/paragraphs using the proper html tag such as a `

` +

+ +## API + +### `async convertText(htmlText:string, options?:Record): Promise` + +Converts the input htmlText to a valid latex string. + +| Name | Type | Optional | Default | Description | +| ------------------------------------------------------------------------- | ---------- | -------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `htmlText` | `string` | No | N/A | Converts the input htmlText to a valid latex string. | +| `options.ignoreBreaks` (`-ib` or `--ignore-breaks`) | `boolean` | Yes | `true` | Instead of replacing `
` with //, ending the line, a simple space character is inserted instead. | +| `options.preferDollarInlineMath` (`-dm` or `--prefer-dollar-inline-math`) | `boolean` | Yes | `false` | Replace `\(` and `\)` with `$`. | +| `options.skipWrappingEquations` ( `-swe` or `--skip-wrapping-equations`) | `boolean` | Yes | `false` | Is an equation is defined in a `p` tag without any other content besides that equation, it will automatically be wrapped in `\[` and `\]`. | +| `options.includeDocumentWrapper` (`-dw` or `--include-document-wrapper`) | `boolean` | Yes | `false` | Adds a document wrapper around the converted text: `\documentclass{article} \begin{document} %converted text% \end{document}`. | +| `options.documentClass` (`-dc` or `--document-class`) | `string` | Yes | `article` | If a document wrapper is added, the document class will be set: `\documentclass{article}`. | +| `options.includePackages` (`-ip` or `--include-packages`) | `string[]` | Yes | `[]` | If a document wrapper is added, a list of used packages will be added via: `\usepackage{packagename}`. If nothing is specified, the list of includes packages will be inferred from the html e.g \cfrac => amsmath, \img => graphicx, \therefore => amssymb | +| `options.title` (`-t` or `--title`) | `string` | Yes | | If a document wrapper is added, the title will be set: `\title{Altered Carbon}`. | +| `options.author` (`-a` or `--author`) | `string` | Yes | | If a document wrapper is added, the author will be set: `\author{Takashi Kovacs}`. | +| `options.includeDate` (`-d` or `--incude-date`) | `boolean` | Yes | `false` | If a document wrapper is added, the current date will be: `\date{\today}`. | +| `options.compilationDir` (`-cdr` or `--compilation-dir`) | `string` | Yes | `process.cwd` | If any images need to be downloaded for the latex compilation, they will be places in a 'images' subdirectory inside this directory. | +| `options.autoGenImageNames` (`-ain` or `--autogen-image-names`) | `boolean` | Yes | `false` | To avoid any weird file names, image files that are downloaded are automatically given a random Id with the extension of the original file. | +| `options.imageWidth` (`-iw` or `--image-width`) | `number` | Yes | | Allows you to set a image width. This would be in the form normally accepted by latex such as: `2cm`. | +| `options.imageHeight` (`-ih` or `--image-height`) | `number` | Yes | | Allows you to set a image height. This would be in the form normally accepted by latex such as: `2cm`. | +| `options.keepImageAspectRatio` (`-kar` or `--keep-aspect-ratio`) | `boolean` | Yes | `false` | Allows you to maintain the aspect ratio of the image. This also requires either the image width property or image height property to be set. | +| `options.debug` (`--debug`) | `boolean` | Yes | `false` | Prints error messages when they occur such as when an image cannot be found at the given url. | + +### `async convertFile(filePath:string, options?:Record): Promise` + +Converts the input file to a valid latex file. + +| Name | Type | Optional | Default | Description | +| ------------------------------------------------------------------------- | ---------- | -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `filePath` | `string` | No | N/A | Path of html file. | +| `options.ignoreBreaks` (`-ib` or `--ignore-breaks`) | `boolean` | Yes | `true` | Instead of replacing `
` with //, ending the line, a simple space character is inserted instead. | +| `options.preferDollarInlineMath` (`-dm` or `--prefer-dollar-inline-math`) | `boolean` | Yes | `false` | Replace `\(` and `\)` with `$`. | +| `options.skipWrappingEquations` ( `-swe` or `--skip-wrapping-equations`) | `boolean` | Yes | `false` | Is an equation is defined in a `p` tag without any other content besides that equation, it will automatically be wrapped in `\[` and `\]`. | +| `options.includeDocumentWrapper` (`-dw` or `--include-document-wrapper`) | `boolean` | Yes | **`true`** | Adds a document wrapper around the converted text: `\documentclass{article} \begin{document} %converted text% \end{document}`. | +| `options.documentClass` (`-dc` or `--document-class`) | `string` | Yes | `article` | If a document wrapper is added, the document class will be set: `\documentclass{article}`. | +| `options.includePackages` (`-ip` or `--include-packages`) | `string[]` | Yes | `[]` | If a document wrapper is added, a list of used packages will be added via: `\usepackage{packagename}`. If nothing is specified, the list of includes packages will be inferred from the html e.g \cfrac => amsmath, \img => graphicx, \therefore => amssymb | +| `options.title` (`-t` or `--title`) | `string` | Yes | | If a document wrapper is added, the title will be set: `\title{Altered Carbon}`. | +| `options.author` (`-a` or `--author`) | `string` | Yes | | If a document wrapper is added, the author will be set: `\author{Takashi Kovacs}`. | +| `options.includeDate` (`-d` or `--incude-date`) | `boolean` | Yes | `false` | If a document wrapper is added, the current date will be: `\date{\today}`. | +| `options.compilationDir` (`-cdr` or `--compilation-dir`) | `string` | Yes | `process.cwd` | If any images need to be downloaded for the latex compilation, they will be places in a 'images' subdirectory inside this directory. | +| `options.autoGenImageNames` (`-ain` or `--autogen-image-names`) | `boolean` | Yes | `true` | To avoid any weird file names, image files that are downloaded are automatically given a random Id with the extension of the original file. | +| `options.imageWidth` (`-iw` or `--image-width`) | `number` | Yes | | Allows you to set a image width. This would be in the form normally accepted by latex such as: `2cm`. | +| `options.imageHeight` (`-ih` or `--image-height`) | `number` | Yes | | Allows you to set a image height. This would be in the form normally accepted by latex such as: `2cm`. | +| `options.keepImageAspectRatio` (`-kar` or `--keep-aspect-ratio`) | `boolean` | Yes | `false` | Allows you to maintain the aspect ratio of the image. This also requires either the image width property or image height property to be set. | +| `options.debug` (`--debug`) | `boolean` | Yes | `false` | Prints error messages when they occur such as when an image cannot be found at the given url. | +| `options.outputFilepath` (`-ofp` or `--output-file-path`) | `string` | Yes | `options.filePath` | The output filepath of the converted file. By default it will overwrite the input file. | + +## FAQ + +### Improving output + +1. Ignoring br tags + Instead designate new sections/paragraphs using the proper html tag such as a `

` + +## Contributors + + + + + + + + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..034e848 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/UPDATE.md b/UPDATE.md new file mode 100644 index 0000000..9e2fcd5 --- /dev/null +++ b/UPDATE.md @@ -0,0 +1,165 @@ +# Upgrade to Version 1 + +- Updating all dependencies +- Updating README +- Adding Typesaftey +- Merging additional functionality as tests from @ +- Switching from Swyac for CLI functionality + +## Moving From SWYAC + +Swyac hasnt been maintained in over four years. Since were doing a full update of this library, now would be the best time to update this dep or replace it. Since its been lacking updates, I've been looking at alternatives that priortize 1. Easy of refactor 2. Maintenance 3. Size. I focused on these items since the CLI isnt very complicated and thus doesnt require any fancy support. Also, since type saftey was added to this library, an additional item that should be supported is 4. typing, and finally planning for the future, 5. ESM readiness. + +### Alternatives + +#### Swyac (for reference) + +- Website: https://sywac.io/ +- GH: https://github.com/sywac/sywac +- NPM: https://www.npmjs.com/package/sywac +- Latest Version: 1.3.0 +- Last Release: March 29 2020 +- Install Size: 103kB +- Package Size: 103kB + +#### @oclif + +- Website: https://oclif.io +- GH: github.com/oclif/core +- NPM: https://www.npmjs.com/package/@oclif/core +- Latest Version: 3.18.2 +- Last Release: Feb 1 2024 +- Install Size: 7.82Mb +- Package Size: 406kB + +**PROs:** + +- very mature +- supports everything under the sun +- has support for ESM and Typescript + +**CONs:** + +- Significantly more complex than what I need +- Requires a large rewrite to handle the structure for commands (doesnt support Fluid syntax) + +#### commander + +- GH: https://github.com/tj/commander.js +- NPM: https://www.npmjs.com/package/commander +- Latest Version: 12.0.0 +- Last Release: Feb 3 2024 +- Install Size: 177kB +- Package Size: 177kB + +**PROs:** + +- very mature +- well maintained + +**CONs:** + +#### @molt/command + +- GH: https://github.com/jasonkuhrt/molt +- NPM: https://www.npmjs.com/package/@molt/command +- Latest Version: 0.9.0 +- Last Release: Sept 23 2023 +- Install Size: 3.38Mb (Looks like src files are also included which would add to this size) +- Package Size: 1.11Mb + +**PROs:** + +- very good type safety +- beautiful cli output +- supports ESM and Typescript +- support Fluid syntax + +**CONs:** + +- very new +- hasnt been worked on for over 6 months +- Quite extensive support for funcitonality that isnt needed here + +#### cac + +- GH: hhttps://github.com/cacjs/cac +- NPM: https://github.com/cacjs/cac?tab=readme-ov-file +- Latest Version: 6.7.14 +- Last Release: Aug 28 2022 +- Install Size: 79.9Kb +- Package Size: 79.9kB + +**PROs:** + +- Mature +- supports ESM and Typescript +- support Fluid syntax +- Simple API + +**CONs:** + +- Hasnt been touched in 2 years +- Requires embedding types into a string format + +#### breadc => similar to cac + +- Website: https://breadc.onekuma.cn/ +- GH: https://github.com/yjl9903/Breadc +- Latest Version: 0.9.7 +- Last Release: Oct 18 2023 +- Install Size: 106kB +- Package Size: 84.0kB + +**PROs:** + +- supports ESM and Typescript +- support Fluid syntax +- Simple API + +**CONs:** + +- Pretty new +- Hasnt been touched in 5 months +- Requires embedding types into a string format + +#### carporal + +- Website: https://caporal.io/ +- GH: https://github.com/mattallty/Caporal.js +- Latest Version: 3.0.0 +- Last Release: Aug 23 2023 +- Install Size: 14.9MB +- Package Size: 97.0kB + +**PROs:** + +- supports ESM and Typescript +- support Fluid syntax +- Simple API +- Supports validation + +**CONs:** + +- Hasnt been touched in 6 months + +#### bandersnatch + +- GH: https://github.com/hongaar/bandersnatch +- NPM: https://www.npmjs.com/package/bandersnatch +- Latest Version: 1.12.13 +- Last Release: Nov 27 2023 +- Install Size: 5.38MB +- Package Size: 119kB + +**PROs:** + +- Validation +- Simple API +- supports ESM and Typescript +- support Fluid syntax + +**CONs:** + +**Notes:** +Looks to be build off yargs diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index f037a1a..0000000 --- a/babel.config.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - node: 'current', - }, - }, - ], - ], -}; diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index a8a5f23..0000000 --- a/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - testEnvironment: 'node', - testRegex: 'test\\/.*\\.js$', - testMatch: null, - testURL: 'http://localhost/', - testTimeout: 15000, - - coverageDirectory: 'coverage', - collectCoverage: true, -}; diff --git a/package.json b/package.json index 9bf0d63..f01179f 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,87 @@ { "name": "html-to-latex", - "description": "convert html to latex", "version": "0.8.0", - "dependencies": { - "entities": "^2.0.0", - "fs-extra": "^9.0.0", - "got": "^11.0.2", - "parse5": "^6.0.0", - "shortid": "^2.2.15", - "sywac": "^1.3.0", - "upath": "^1.2.0" + "description": "A library for converting HTML to LATEX", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/jdalrymple/html-to-latex.git" }, - "devDependencies": { - "@babel/core": "^7.9.0", - "@babel/preset-env": "^7.9.5", - "babel-jest": "^25.4.0", - "codecov": "^3.6.5", - "cz-conventional-changelog": "3.1.0", - "eslint": "^6.8.0", - "eslint-config-airbnb-base": "^14.1.0", - "eslint-config-prettier": "^6.11.0", - "eslint-plugin-import": "^2.20.2", - "eslint-plugin-jest": "^23.8.2", - "eslint-plugin-prettier": "^3.1.3", - "jest": "^25.4.0", - "prettier": "^2.0.5", - "rollup": "^2.7.3", - "rollup-plugin-preserve-shebangs": "^0.2.0", - "tempy": "^0.5.0" + "bugs": { + "url": "https://github.com/jdalrymple/html-to-latex/issues" }, - "files": [ - "dist" + "homepage": "https://github.com/jdalrymple/html-to-latex", + "author": "Justin Dalrymple", + "keywords": [ + "latex", + "html", + "convert" ], - "license": "MIT", "bin": { - "html2latex": "dist/bin.js" + "html-to-latex": "dist/index-bin.js", + "html2latex": "dist/index-bin.mjs", + "h2l": "dist/index-bin.mjs" + }, + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } }, - "main": "dist/index.js", + "files": [ + "dist" + ], "scripts": { - "build": "rollup -c", - "commit": "npx git-cz", - "test": "jest test", - "lint": "prettier --check '{src,test}/**/*.js' && eslint '{src,test}/**/*/*.js'", - "lint:fix": "prettier --write '{src,test}/**/*.js' && eslint '{src,test}/**/*/*.js' --fix" + "build": "tsup src/index.mts --format esm,cjs --dts --treeshake && tsup src/index-bin.mts --format esm --treeshake", + "format": "pnpm format:src && pnpm format:docs", + "format:docs": "prettier './(*.json|*.yml|*.md|*.(c|m)js|*.(c|m)ts)' --ignore-path ./.prettierignore --check", + "format:fix": "pnpm format:src --write && pnpm format:docs --write", + "format:src": "prettier '{src,test}/**/(*.(c|m)js|*.(c|m)ts)' --ignore-path ./.prettierignore --check", + "lint": "eslint 'src/**/*.{*(c|m)js,*(c|m)ts}'", + "lint:fix": "pnpm lint --fix", + "release": "auto shipit", + "test:unit": "vitest run --coverage", + "test:types": "tsc" }, - "config": { - "commitizen": { - "path": "./node_modules/cz-conventional-changelog" - } + "resolutions": { + "all-contributors-cli": "6.26.1" + }, + "dependencies": { + "@commander-js/extra-typings": "^12.0.0", + "commander": "^12.0.0", + "entities": "^4.5.0", + "nanoid": "^5.0.6", + "parse5": "^7.1.2", + "upath": "^2.0.1" + }, + "devDependencies": { + "@auto-it/all-contributors": "^11.1.1", + "@auto-it/core": "^11.1.1", + "@auto-it/first-time-contributor": "^11.1.1", + "@auto-it/omit-commits": "^11.1.1", + "@auto-it/omit-release-notes": "^11.1.1", + "@auto-it/released": "^11.1.1", + "@types/node": "^20.11.20", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", + "@vitest/coverage-istanbul": "^1.3.1", + "auto": "^11.1.1", + "eslint": "^8.57.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prettier": "^5.1.3", + "prettier": "^3.2.5", + "tempy": "^3.1.0", + "tsup": "^8.0.2", + "typescript": "^5.3.3", + "vitest": "^1.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..8e97728 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5081 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + all-contributors-cli: 6.26.1 + +dependencies: + '@commander-js/extra-typings': + specifier: ^12.0.0 + version: 12.0.0(commander@12.0.0) + commander: + specifier: ^12.0.0 + version: 12.0.0 + entities: + specifier: ^4.5.0 + version: 4.5.0 + nanoid: + specifier: ^5.0.6 + version: 5.0.6 + parse5: + specifier: ^7.1.2 + version: 7.1.2 + upath: + specifier: ^2.0.1 + version: 2.0.1 + +devDependencies: + '@auto-it/all-contributors': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/core': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/first-time-contributor': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/omit-commits': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/omit-release-notes': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/released': + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@types/node': + specifier: ^20.11.20 + version: 20.11.20 + '@typescript-eslint/eslint-plugin': + specifier: ^7.1.0 + version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': + specifier: ^7.1.0 + version: 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@vitest/coverage-istanbul': + specifier: ^1.3.1 + version: 1.3.1(vitest@1.3.1) + auto: + specifier: ^11.1.1 + version: 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-config-airbnb-base: + specifier: ^15.0.0 + version: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@8.57.0) + eslint-import-resolver-typescript: + specifier: ^3.6.1 + version: 3.6.1(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: + specifier: ^2.29.1 + version: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-prettier: + specifier: ^5.1.3 + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) + prettier: + specifier: ^3.2.5 + version: 3.2.5 + tempy: + specifier: ^3.1.0 + version: 3.1.0 + tsup: + specifier: ^8.0.2 + version: 8.0.2(typescript@5.3.3) + typescript: + specifier: ^5.3.3 + version: 5.3.3 + vitest: + specifier: ^1.3.1 + version: 1.3.1(@types/node@20.11.20) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.22 + dev: true + + /@auto-it/all-contributors@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-MSiif/W/cWskqRew1V5xO3Z3VCP3evsaRyl3paTzw1DAI6o7QRGW/M5qSZhCDqPg1v7C43/59yhhBPzlAvf/Sg==} + dependencies: + '@auto-it/bot-list': 11.1.1 + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@octokit/rest': 18.12.0 + all-contributors-cli: 6.26.1 + anymatch: 3.1.3 + await-to-js: 3.0.0 + endent: 2.1.0 + env-ci: 5.5.0 + fp-ts: 2.16.2 + fromentries: 1.3.2 + io-ts: 2.2.21(fp-ts@2.16.2) + tslib: 2.1.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/bot-list@11.1.1: + resolution: {integrity: sha512-uKZ08KC9FUjMBYqiizZ3VlXyEAeRHEAJaeNMqQFPi0jFKRtX/Dm4tAhDXqfQeuOuAsUHNh5Pp+4zOX2RmTPZaA==} + engines: {node: '>=10.x'} + dev: true + + /@auto-it/core@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-CIQYqJG/pXmWsQjgbjMF6qnwAu7Klrpm5fWHrXpzIEq/3qQfgGmTkauuJRSz9bM5z6pHHCjT1eypVV/EDj9ijg==} + peerDependencies: + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@auto-it/bot-list': 11.1.1 + '@endemolshinegroup/cosmiconfig-typescript-loader': 3.0.2(cosmiconfig@7.0.0)(typescript@5.3.3) + '@octokit/core': 3.6.0 + '@octokit/plugin-enterprise-compatibility': 1.3.0 + '@octokit/plugin-retry': 3.0.9 + '@octokit/plugin-throttling': 3.7.0(@octokit/core@3.6.0) + '@octokit/rest': 18.12.0 + '@types/node': 20.11.20 + await-to-js: 3.0.0 + chalk: 4.1.2 + cosmiconfig: 7.0.0 + deepmerge: 4.3.1 + dotenv: 8.6.0 + endent: 2.1.0 + enquirer: 2.4.1 + env-ci: 5.5.0 + fast-glob: 3.3.2 + fp-ts: 2.16.2 + fromentries: 1.3.2 + gitlog: 4.0.8 + https-proxy-agent: 5.0.1 + import-cwd: 3.0.0 + import-from: 3.0.0 + io-ts: 2.2.21(fp-ts@2.16.2) + lodash.chunk: 4.2.0 + log-symbols: 4.1.0 + node-fetch: 2.6.7 + parse-author: 2.0.0 + parse-github-url: 1.0.2 + pretty-ms: 7.0.1 + requireg: 0.2.2 + semver: 7.5.4 + signale: 1.4.0 + tapable: 2.2.1 + terminal-link: 2.1.1 + tinycolor2: 1.6.0 + ts-node: 10.9.2(@types/node@20.11.20)(typescript@5.3.3) + tslib: 2.1.0 + type-fest: 0.21.3 + typescript: 5.3.3 + typescript-memoize: 1.1.1 + url-join: 4.0.1 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - encoding + - supports-color + dev: true + + /@auto-it/first-time-contributor@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-xyKULf7+EoaPUZdYE1jVLMo4GUUxiIU5Q9ENdcTrCsw9Y4jSIdCBZKR+wxbxZNdqsJHnLGfAaW+SbLY8OrN2ng==} + dependencies: + '@auto-it/bot-list': 11.1.1 + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + array.prototype.flatmap: 1.3.2 + endent: 2.1.0 + tslib: 2.1.0 + url-join: 4.0.1 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/npm@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-I7qWPdU2goCmqdvAEpa6yGwQmzx5YXEsZywqs6uTQXIDuGbFzNt/7jwJNt8p/MNE8M0ra8FJ05eHavBLFZuEfg==} + dependencies: + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/package-json-utils': 11.1.1 + await-to-js: 3.0.0 + endent: 2.1.0 + env-ci: 5.5.0 + fp-ts: 2.16.2 + get-monorepo-packages: 1.2.0 + io-ts: 2.2.21(fp-ts@2.16.2) + registry-url: 5.1.0 + semver: 7.5.4 + tslib: 2.1.0 + typescript-memoize: 1.1.1 + url-join: 4.0.1 + user-home: 2.0.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/omit-commits@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-+oh0lSWBEvOcBIdkkU9ITSFz+JEnOmX6Y538WUfEegbljR0XMyOAj/LI/9NdtmuKkBKDTXJf247S+7LJGrvPHQ==} + dependencies: + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + fp-ts: 2.16.2 + io-ts: 2.2.21(fp-ts@2.16.2) + tslib: 2.1.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/omit-release-notes@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-5xZYmqsqkMOVrQPpc9MFDuChAAc4uPOLtFe1TgVTQS9w7Z3vqMwlozHuDUkaSAsCL4ycfHJ6/aiaslAG2+8p7Q==} + dependencies: + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + fp-ts: 2.16.2 + io-ts: 2.2.21(fp-ts@2.16.2) + tslib: 2.1.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/package-json-utils@11.1.1: + resolution: {integrity: sha512-hk6wKuP7fPonXnP/blPHYS4iQaKZ6s+dVBRPSW7pjWZv6H/A131mWVSQC59nhe8lqZhbQ2MrDH4xxfhYnq21sA==} + engines: {node: '>=10.x'} + dependencies: + parse-author: 2.0.0 + parse-github-url: 1.0.2 + dev: true + + /@auto-it/released@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-iRUebl2q5V7hFEgScGVUMUVoOXrFFi5O280hUCpZxmd6kkG2v7Kl+Weii5zKpd7YSqG0HibJCD+LVwPClAfrCA==} + dependencies: + '@auto-it/bot-list': 11.1.1 + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + deepmerge: 4.3.1 + fp-ts: 2.16.2 + io-ts: 2.2.21(fp-ts@2.16.2) + tslib: 2.1.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@auto-it/version-file@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-KHKunip2nXWKd7zJ0hdALojY+E6sTdmxuq9SXYgTMXUcZw2BtxunVSK1hb2wmS6iUH4CCILk12dHksAO5BFzeQ==} + dependencies: + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + fp-ts: 2.16.2 + io-ts: 2.2.21(fp-ts@2.16.2) + semver: 7.5.4 + tslib: 1.10.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + dev: true + + /@babel/compat-data@7.23.5: + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.9: + resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.9) + '@babel/helpers': 7.23.9 + '@babel/parser': 7.23.9 + '@babel/template': 7.23.9 + '@babel/traverse': 7.23.9 + '@babel/types': 7.23.9 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.6: + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.9 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.22 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.3 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.23.9 + '@babel/types': 7.23.9 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.9 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.9 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.9 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.9 + dev: true + + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.9: + resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.23.9 + '@babel/traverse': 7.23.9 + '@babel/types': 7.23.9 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser@7.23.9: + resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.9 + dev: true + + /@babel/runtime@7.23.9: + resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true + + /@babel/template@7.23.9: + resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 + dev: true + + /@babel/traverse@7.23.9: + resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.9: + resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@commander-js/extra-typings@12.0.0(commander@12.0.0): + resolution: {integrity: sha512-7zGCwtRKOJ978LCuEZbQ9ZmLdrRkNNASphEO5i9MZb6HfOk7KfsA3f4oXqYDhko4tNrU3GmZTlHqQ/nRlYtYSw==} + peerDependencies: + commander: ~12.0.0 + dependencies: + commander: 12.0.0 + dev: false + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@endemolshinegroup/cosmiconfig-typescript-loader@3.0.2(cosmiconfig@7.0.0)(typescript@5.3.3): + resolution: {integrity: sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==} + engines: {node: '>=10.0.0'} + peerDependencies: + cosmiconfig: '>=6' + dependencies: + cosmiconfig: 7.0.0 + lodash.get: 4.4.2 + make-error: 1.3.6 + ts-node: 9.1.1(typescript@5.3.3) + tslib: 2.6.2 + transitivePeerDependencies: + - typescript + dev: true + + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + 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.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + 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.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + 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@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.22 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.22: + resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + 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.17.0 + dev: true + + /@octokit/auth-token@2.5.0: + resolution: {integrity: sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==} + dependencies: + '@octokit/types': 6.41.0 + dev: true + + /@octokit/core@3.6.0: + resolution: {integrity: sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==} + dependencies: + '@octokit/auth-token': 2.5.0 + '@octokit/graphql': 4.8.0 + '@octokit/request': 5.6.3 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/endpoint@6.0.12: + resolution: {integrity: sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==} + dependencies: + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/graphql@4.8.0: + resolution: {integrity: sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==} + dependencies: + '@octokit/request': 5.6.3 + '@octokit/types': 6.41.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/openapi-types@12.11.0: + resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + dev: true + + /@octokit/plugin-enterprise-compatibility@1.3.0: + resolution: {integrity: sha512-h34sMGdEOER/OKrZJ55v26ntdHb9OPfR1fwOx6Q4qYyyhWA104o11h9tFxnS/l41gED6WEI41Vu2G2zHDVC5lQ==} + dependencies: + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + dev: true + + /@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0): + resolution: {integrity: sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==} + peerDependencies: + '@octokit/core': '>=2' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + dev: true + + /@octokit/plugin-request-log@1.0.4(@octokit/core@3.6.0): + resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 3.6.0 + dev: true + + /@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0): + resolution: {integrity: sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + dev: true + + /@octokit/plugin-retry@3.0.9: + resolution: {integrity: sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==} + dependencies: + '@octokit/types': 6.41.0 + bottleneck: 2.19.5 + dev: true + + /@octokit/plugin-throttling@3.7.0(@octokit/core@3.6.0): + resolution: {integrity: sha512-qrKT1Yl/KuwGSC6/oHpLBot3ooC9rq0/ryDYBCpkRtoj+R8T47xTMDT6Tk2CxWopFota/8Pi/2SqArqwC0JPow==} + peerDependencies: + '@octokit/core': ^3.5.0 + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + bottleneck: 2.19.5 + dev: true + + /@octokit/request-error@2.1.0: + resolution: {integrity: sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==} + dependencies: + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: true + + /@octokit/request@5.6.3: + resolution: {integrity: sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==} + dependencies: + '@octokit/endpoint': 6.0.12 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + node-fetch: 2.7.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/rest@18.12.0: + resolution: {integrity: sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==} + dependencies: + '@octokit/core': 3.6.0 + '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0) + '@octokit/plugin-request-log': 1.0.4(@octokit/core@3.6.0) + '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0) + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/types@6.41.0: + resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} + dependencies: + '@octokit/openapi-types': 12.11.0 + dev: true + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@rollup/rollup-android-arm-eabi@4.9.6: + resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.9.6: + resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.9.6: + resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.9.6: + resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.9.6: + resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.9.6: + resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.9.6: + resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.9.6: + resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.9.6: + resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.9.6: + resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.9.6: + resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.9.6: + resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.9.6: + resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: true + + /@types/command-line-args@5.2.3: + resolution: {integrity: sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==} + dev: true + + /@types/command-line-usage@5.0.4: + resolution: {integrity: sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==} + dev: true + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/node@20.11.20: + resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: true + + /@types/semver@7.5.6: + resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} + dev: true + + /@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.0 + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.0 + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@7.1.0: + resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/visitor-keys': 7.1.0 + dev: true + + /@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.57.0 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@7.1.0: + resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@7.1.0(typescript@5.3.3): + resolution: {integrity: sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/visitor-keys': 7.1.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.6 + '@typescript-eslint/scope-manager': 7.1.0 + '@typescript-eslint/types': 7.1.0 + '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) + eslint: 8.57.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@7.1.0: + resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vitest/coverage-istanbul@1.3.1(vitest@1.3.1): + resolution: {integrity: sha512-aBVgQ2eY9gzrxBJjGKbWgatTU2w1CacEx0n8OMctPzl9836KqoM5X/WigJpjM7wZEtX2N0ZTE5KDGPmVM+o2Wg==} + peerDependencies: + vitest: 1.3.1 + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + magicast: 0.3.3 + picocolors: 1.0.0 + test-exclude: 6.0.0 + vitest: 1.3.1(@types/node@20.11.20) + transitivePeerDependencies: + - supports-color + dev: true + + /@vitest/expect@1.3.1: + resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==} + dependencies: + '@vitest/spy': 1.3.1 + '@vitest/utils': 1.3.1 + chai: 4.4.1 + dev: true + + /@vitest/runner@1.3.1: + resolution: {integrity: sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==} + dependencies: + '@vitest/utils': 1.3.1 + p-limit: 5.0.0 + pathe: 1.1.2 + dev: true + + /@vitest/snapshot@1.3.1: + resolution: {integrity: sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==} + dependencies: + magic-string: 0.30.7 + pathe: 1.1.2 + pretty-format: 29.7.0 + dev: true + + /@vitest/spy@1.3.1: + resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==} + dependencies: + tinyspy: 2.2.0 + dev: true + + /@vitest/utils@1.3.1: + resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==} + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + 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 + + /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 + + /all-contributors-cli@6.26.1: + resolution: {integrity: sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==} + engines: {node: '>=4'} + hasBin: true + dependencies: + '@babel/runtime': 7.23.9 + async: 3.2.5 + chalk: 4.1.2 + didyoumean: 1.2.2 + inquirer: 7.3.3 + json-fixer: 1.6.15 + lodash: 4.17.21 + node-fetch: 2.7.0 + pify: 5.0.0 + yargs: 15.4.1 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - encoding + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + 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 + + /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 + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-back@3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} + dev: true + + /array-back@4.0.2: + resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} + engines: {node: '>=8'} + dev: true + + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.4 + dev: true + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + + /array-union@1.0.2: + resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} + engines: {node: '>=0.10.0'} + dependencies: + array-uniq: 1.0.3 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + dev: true + + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.2 + dev: true + + /assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /author-regex@1.0.0: + resolution: {integrity: sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==} + engines: {node: '>=0.8'} + dev: true + + /auto@11.1.1(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-mOucdDWMjtuBDH8phH9Z0s1dD4uFrFIhYQ/Zh4wCH2uB3eEf8qZbu20DLOWCfj1zEUU2gxqVAuqJD4OyLWvaSQ==} + engines: {node: '>=10.x'} + hasBin: true + dependencies: + '@auto-it/core': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/npm': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/released': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + '@auto-it/version-file': 11.1.1(@types/node@20.11.20)(typescript@5.3.3) + await-to-js: 3.0.0 + chalk: 4.1.2 + command-line-application: 0.10.1 + endent: 2.1.0 + module-alias: 2.2.3 + signale: 1.4.0 + terminal-link: 2.1.1 + tslib: 2.1.0 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - encoding + - supports-color + - typescript + dev: true + + /available-typed-arrays@1.0.6: + resolution: {integrity: sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==} + engines: {node: '>= 0.4'} + dev: true + + /await-to-js@3.0.0: + resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} + engines: {node: '>=6.0.0'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + 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 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.22.3: + resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001583 + electron-to-chromium: 1.4.656 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.22.3) + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /bundle-require@4.0.2(esbuild@0.19.12): + resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.19.12 + load-tsconfig: 0.2.5 + dev: true + + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.2.0 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /caniuse-lite@1.0.30001583: + resolution: {integrity: sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==} + dev: true + + /chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + 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 + + /chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: true + + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 + 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.3 + dev: true + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + dev: true + + /cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.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 + + /command-line-application@0.10.1: + resolution: {integrity: sha512-PWZ4nRkz09MbBRocqEe/Fil3RjTaMNqw0didl1n/i3flDcw/vecVfvsw3r+ZHhGs4BOuW7sk3cEYSdfM3Wv5/Q==} + dependencies: + '@types/command-line-args': 5.2.3 + '@types/command-line-usage': 5.0.4 + chalk: 2.4.2 + command-line-args: 5.2.1 + command-line-usage: 6.1.3 + meant: 1.0.3 + remove-markdown: 0.3.0 + tslib: 1.10.0 + dev: true + + /command-line-args@5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + find-replace: 3.0.0 + lodash.camelcase: 4.3.0 + typical: 4.0.0 + dev: true + + /command-line-usage@6.1.3: + resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + chalk: 2.4.2 + table-layout: 1.0.2 + typical: 5.2.0 + dev: true + + /commander@12.0.0: + resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} + engines: {node: '>=18'} + dev: false + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /confusing-browser-globals@1.0.11: + resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /cosmiconfig@7.0.0: + resolution: {integrity: sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + 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@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + 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@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: true + + /dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + 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 + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: true + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob@2.2.2: + resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} + engines: {node: '>=4'} + dependencies: + path-type: 3.0.0 + 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 + + /dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /electron-to-chromium@1.4.656: + resolution: {integrity: sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==} + 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 + + /endent@2.1.0: + resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} + dependencies: + dedent: 0.7.0 + fast-json-parse: 1.0.3 + objectorarray: 1.0.5 + dev: true + + /enhanced-resolve@5.15.0: + resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + + /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.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.6 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.4 + 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.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.1.0 + safe-regex-test: 1.0.2 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.14 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.2 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + 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.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + 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-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.2 + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + object.assign: 4.1.5 + object.entries: 1.1.7 + semver: 6.3.1 + dev: true + + /eslint-config-prettier@9.1.0(eslint@8.57.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: 4.3.4 + enhanced-resolve: 5.15.0 + eslint: 8.57.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + fast-glob: 3.3.2 + get-tsconfig: 4.7.2 + is-core-module: 2.13.1 + is-glob: 4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + 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': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + 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': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + hasown: 2.0.0 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + 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.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.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.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + 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@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.5 + 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 + + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.2.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true + + /external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + 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-parse@1.0.3: + resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} + 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.17.0: + resolution: {integrity: sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==} + dependencies: + reusify: 1.0.4 + 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.2.0 + 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-replace@3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + 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 + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + + /fp-ts@2.16.2: + resolution: {integrity: sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==} + dev: true + + /fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + 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.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-monorepo-packages@1.2.0: + resolution: {integrity: sha512-aDP6tH+eM3EuVSp3YyCutOcFS4Y9AhRRH9FAd+cjtR/g63Hx+DCXdKoP1ViRPUJz5wm+BOEXB4FhoffGHxJ7jQ==} + dependencies: + globby: 7.1.1 + load-json-file: 4.0.0 + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + + /gitlog@4.0.8: + resolution: {integrity: sha512-FcTLP7Rc0H1vWXD+J/aj5JS1uiCEBblcYXlcacRAT73N26OMYFFzrBXYmDozmWlV2K7zwK5PrH16/nuRNhqSlQ==} + engines: {node: '>= 10.x'} + dependencies: + debug: 4.3.4 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + 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@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + 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@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + 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.1 + 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.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /globby@7.1.1: + resolution: {integrity: sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==} + engines: {node: '>=4'} + dependencies: + array-union: 1.0.2 + dir-glob: 2.2.2 + glob: 7.2.3 + ignore: 3.3.10 + pify: 3.0.0 + slash: 1.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + 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.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + 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.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + 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 + + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: true + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /ignore@3.3.10: + resolution: {integrity: sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==} + dev: true + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + dev: true + + /import-cwd@3.0.0: + resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} + engines: {node: '>=8'} + dependencies: + import-from: 3.0.0 + 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@3.0.0: + resolution: {integrity: sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + 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 + + /inquirer@7.3.3: + resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} + engines: {node: '>=8.0.0'} + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + run-async: 2.4.1 + rxjs: 6.6.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + dev: true + + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + + /io-ts@2.2.21(fp-ts@2.16.2): + resolution: {integrity: sha512-zz2Z69v9ZIC3mMLYWIeoUcwWD6f+O7yP92FMVVaXEOSZH1jnVBmET/urd/uoarD1WGBY4rCj8TAyMPzsGNzMFQ==} + peerDependencies: + fp-ts: ^2.5.0 + dependencies: + fp-ts: 2.16.2 + dev: true + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + 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.5 + has-tostringtag: 1.0.2 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + 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-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + 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.2 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + 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.5 + has-tostringtag: 1.0.2 + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + 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-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.14 + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.5 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@6.0.1: + resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.23.9 + '@babel/parser': 7.23.9 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.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-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-tokens@8.0.3: + resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==} + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-fixer@1.6.15: + resolution: {integrity: sha512-TuDuZ5KrgyjoCIppdPXBMqiGfota55+odM+j2cQ5rt/XKyKmqGB3Whz1F8SN8+60yYGy/Nu5lbRZ+rx8kBIvBw==} + engines: {node: '>=10'} + dependencies: + '@babel/runtime': 7.23.9 + chalk: 4.1.2 + pegjs: 0.10.0 + 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 + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + 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@3.0.0: + resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + engines: {node: '>=14'} + 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.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + dev: true + + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} + engines: {node: '>=14'} + dependencies: + mlly: 1.5.0 + pkg-types: 1.0.3 + 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.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + dev: true + + /lodash.chunk@4.2.0: + resolution: {integrity: sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==} + dev: true + + /lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + 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@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + dependencies: + get-func-name: 2.0.2 + dev: true + + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /magic-string@0.30.7: + resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /magicast@0.3.3: + resolution: {integrity: sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==} + dependencies: + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 + source-map-js: 1.0.2 + dev: true + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /meant@1.0.3: + resolution: {integrity: sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw==} + 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 + + /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 + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + + /mlly@1.5.0: + resolution: {integrity: sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==} + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.0.3 + ufo: 1.4.0 + dev: true + + /module-alias@2.2.3: + resolution: {integrity: sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + 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.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nanoid@5.0.6: + resolution: {integrity: sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==} + engines: {node: ^18 || >=20} + hasBin: true + dev: false + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /nested-error-stacks@2.0.1: + resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} + dev: true + + /node-fetch@2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + 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-run-path@5.2.0: + resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.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.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /objectorarray@1.0.5: + resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==} + 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 + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /os-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + dev: true + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + 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@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + 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-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-author@2.0.0: + resolution: {integrity: sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==} + engines: {node: '>=0.10.0'} + dependencies: + author-regex: 1.0.0 + dev: true + + /parse-github-url@1.0.2: + resolution: {integrity: sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==} + engines: {node: '>=0.10.0'} + hasBin: true + 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.23.5 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parse-ms@2.1.0: + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} + dev: true + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: false + + /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-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + dev: true + + /path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + dependencies: + pify: 3.0.0 + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true + + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /pegjs@0.10.0: + resolution: {integrity: sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==} + engines: {node: '>=0.10'} + hasBin: true + 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 + + /pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + 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.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.1 + mlly: 1.5.0 + pathe: 1.1.2 + dev: true + + /postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.0.0 + yaml: 2.3.4 + dev: true + + /postcss@8.4.34: + resolution: {integrity: sha512-4eLTO36woPSocqZ1zIrFD2K1v6wH7pY1uBh0JIM2KKfrVtGvPFiAku6aNOP0W1Wr9qwnaCsF0Z+CrVnryB2A8Q==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + 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-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /pretty-ms@7.0.1: + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} + dependencies: + parse-ms: 2.1.0 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + 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@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /reduce-flatten@2.0.0: + resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} + engines: {node: '>=6'} + dev: true + + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: true + + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + + /registry-url@5.1.0: + resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} + engines: {node: '>=8'} + dependencies: + rc: 1.2.8 + dev: true + + /remove-markdown@0.3.0: + resolution: {integrity: sha512-5392eIuy1mhjM74739VunOlsOYKjsH82rQcTBlJ1bkICVC3dQ3ksQzTHh4jGHQFnM+1xzLzcFOMH+BofqXhroQ==} + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true + + /requireg@0.2.2: + resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} + engines: {node: '>= 4.0.0'} + dependencies: + nested-error-stacks: 2.0.1 + rc: 1.2.8 + resolve: 1.7.1 + 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-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /resolve@1.7.1: + resolution: {integrity: sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==} + dependencies: + path-parse: 1.0.7 + dev: true + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + 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.2.3 + dev: true + + /rollup@4.9.6: + resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.9.6 + '@rollup/rollup-android-arm64': 4.9.6 + '@rollup/rollup-darwin-arm64': 4.9.6 + '@rollup/rollup-darwin-x64': 4.9.6 + '@rollup/rollup-linux-arm-gnueabihf': 4.9.6 + '@rollup/rollup-linux-arm64-gnu': 4.9.6 + '@rollup/rollup-linux-arm64-musl': 4.9.6 + '@rollup/rollup-linux-riscv64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-musl': 4.9.6 + '@rollup/rollup-win32-arm64-msvc': 4.9.6 + '@rollup/rollup-win32-ia32-msvc': 4.9.6 + '@rollup/rollup-win32-x64-msvc': 4.9.6 + fsevents: 2.3.3 + dev: true + + /run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + dependencies: + tslib: 1.14.1 + dev: true + + /safe-array-concat@1.1.0: + resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.2: + resolution: {integrity: sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true + + /set-function-length@1.2.0: + resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + 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.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + 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 + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + 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 + + /slash@1.0.0: + resolution: {integrity: sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==} + engines: {node: '>=0.10.0'} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + 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 + + /stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + + /std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + 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.1.0 + dev: true + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + 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.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + 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-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + 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@2.0.0: + resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==} + dependencies: + js-tokens: 8.0.3 + dev: true + + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 10.3.10 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + 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 + + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.2 + dev: true + + /table-layout@1.0.2: + resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + deep-extend: 0.6.0 + typical: 5.2.0 + wordwrapjs: 4.0.1 + dev: true + + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + + /tempy@3.1.0: + resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} + engines: {node: '>=14.16'} + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + dev: true + + /terminal-link@2.1.1: + resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} + engines: {node: '>=8'} + dependencies: + ansi-escapes: 4.3.2 + supports-hyperlinks: 2.3.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.2.3 + minimatch: 3.1.2 + 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 + + /tinybench@2.6.0: + resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==} + dev: true + + /tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + dev: true + + /tinypool@0.8.2: + resolution: {integrity: sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy@2.2.0: + resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} + engines: {node: '>=14.0.0'} + dev: true + + /tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + dependencies: + os-tmpdir: 1.0.2 + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + 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.1 + dev: true + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + + /ts-api-utils@1.0.3(typescript@5.3.3): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.3.3 + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /ts-node@10.9.2(@types/node@20.11.20)(typescript@5.3.3): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.11.20 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.3.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /ts-node@9.1.1(typescript@5.3.3): + resolution: {integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==} + engines: {node: '>=10.0.0'} + hasBin: true + peerDependencies: + typescript: '>=2.7' + dependencies: + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + source-map-support: 0.5.21 + typescript: 5.3.3 + yn: 3.1.1 + dev: true + + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib@1.10.0: + resolution: {integrity: sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==} + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.1.0: + resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tsup@8.0.2(typescript@5.3.3): + resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.2(esbuild@0.19.12) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.19.12 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.2 + resolve-from: 5.0.0 + rollup: 4.9.6 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tree-kill: 1.2.2 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + - ts-node + 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.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.6 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.13 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.13 + dev: true + + /typescript-memoize@1.1.1: + resolution: {integrity: sha512-GQ90TcKpIH4XxYTI2F98yEQYZgjNMOGPpOgdjIBhaLaWji5HPWlRnZ4AeA1hfBxtY7bCGDJsqDDHk/KaHOl5bA==} + dev: true + + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typical@4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} + dev: true + + /typical@5.2.0: + resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} + engines: {node: '>=8'} + dev: true + + /ufo@1.4.0: + resolution: {integrity: sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==} + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.5 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + dependencies: + crypto-random-string: 4.0.0 + dev: true + + /universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + dev: true + + /upath@2.0.1: + resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} + engines: {node: '>=4'} + dev: false + + /update-browserslist-db@1.0.13(browserslist@4.22.3): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.3 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + dev: true + + /user-home@2.0.0: + resolution: {integrity: sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==} + engines: {node: '>=0.10.0'} + dependencies: + os-homedir: 1.0.2 + dev: true + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + + /vite-node@1.3.1(@types/node@20.11.20): + resolution: {integrity: sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.0 + vite: 5.0.12(@types/node@20.11.20) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite@5.0.12(@types/node@20.11.20): + resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.11.20 + esbuild: 0.19.12 + postcss: 8.4.34 + rollup: 4.9.6 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vitest@1.3.1(@types/node@20.11.20): + resolution: {integrity: sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.3.1 + '@vitest/ui': 1.3.1 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/node': 20.11.20 + '@vitest/expect': 1.3.1 + '@vitest/runner': 1.3.1 + '@vitest/snapshot': 1.3.1 + '@vitest/spy': 1.3.1 + '@vitest/utils': 1.3.1 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.7 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 2.0.0 + tinybench: 2.6.0 + tinypool: 0.8.2 + vite: 5.0.12(@types/node@20.11.20) + vite-node: 1.3.1(@types/node@20.11.20) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + 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-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: true + + /which-typed-array@1.1.14: + resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.6 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + 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 + + /wordwrapjs@4.0.1: + resolution: {integrity: sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==} + engines: {node: '>=8.0.0'} + dependencies: + reduce-flatten: 2.0.0 + typical: 5.2.0 + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + 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 + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} + engines: {node: '>= 14'} + dev: true + + /yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: true + + /yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + 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/rollup.config.js b/rollup.config.js deleted file mode 100644 index c98c44f..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import { preserveShebangs } from 'rollup-plugin-preserve-shebangs'; -import pkg from "./package.json"; - -export default [{ - input: "src/bin.js", - external: [ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}) - ], - output: [ - { - file: pkg.bin.html2latex, - format: "cjs" - } - ], - plugins: [ - preserveShebangs() - ] -}, -{ - input: "src/convert.js", - external: [ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}) - ], - output: [ - { - file: pkg.main, - format: "cjs" - } - ] -}]; \ No newline at end of file diff --git a/src/bin.js b/src/bin.js deleted file mode 100644 index 6502f44..0000000 --- a/src/bin.js +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env node -/* eslint no-console: 0 */ - -import program from 'sywac'; -import { extname, basename } from 'path'; -import { convertFile } from './convert'; - -// Add default settings -program - .version('-v, --version') - .help('-h, --help') - .epilogue('Copyright 2020') - .command('convert-file', { - desc: 'Convert HTML to Latex', - setup: (args) => { - args - .positional('[--ifp] ', { - type: 'string', - }) - .string('-ofp --output-file-path', { - group: 'Output Options', - }) - .boolean('-ib --ignore-breaks', { - group: 'Parsing Options', - defaultValue: true, - }) - .boolean('-dm --prefer-dollar-inline-math', { - group: 'Parsing Options', - defaultValue: false, - }) - .boolean('-swe --skip-wrapping-equations', { - group: 'Parsing Options', - defaultValue: false, - }) - .boolean('-dw --include-document-wrapper', { - group: 'Parsing Options', - defaultValue: false, - }) - .string('-dc --document-class', { - group: 'Parsing Options', - defaultValue: 'article', - }) - .array('-ip --include-packages', { - group: 'Parsing Options', - }) - .string('-t --title', { - group: 'Parsing Options', - }) - .string('-a --author', { - group: 'Parsing Options', - }) - .boolean('-d --include-date', { - group: 'Parsing Options', - }) - .string('-cdr --compilation-dir', { - group: 'Image Parsing Options', - default: process.cwd(), - }) - .boolean('-ain --autogen-image-names', { - group: 'Image Parsing Options', - defaultValue: true, - }) - .string('-iw --image-width', { - group: 'Image Parsing Options', - }) - .string('-ih --image-height', { - group: 'Image Parsing Options', - }) - .boolean('-kar --keep-image-aspect-ratio', { - group: 'Image Parsing Options', - default: false, - }) - .boolean('--debug', { - group: 'Image Parsing Options', - defaultValue: false, - }); - }, - run: async (args) => { - await convertFile(args.ifp, args.ofp, { - autoGenImageNames: args.ain, - includeDocumentWrapper: args.dw, - documentClass: args.dc, - includePackages: args.ip, - compilationDir: args.cpr, - preferDollarInlineMath: args.dm, - skipWrappingEquations: args.swe, - debug: args.debug, - imageWidth: args.iw, - imageHeight: args.ih, - keepImageAspectRatio: args.kar, - title: args.t, - includeDate: args.d, - author: args.a, - ignoreBreaks: args.ib, - }); - }, - }); - -// Parse input -program.parse().then(({ output }) => { - console.log(output); -}); diff --git a/src/convert.js b/src/convert.js deleted file mode 100644 index c4f3368..0000000 --- a/src/convert.js +++ /dev/null @@ -1,318 +0,0 @@ -import { parseFragment } from 'parse5'; -import { decodeHTML } from 'entities'; -import { outputFile, readFile, pathExists, ensureDir } from 'fs-extra'; -import { resolve, basename, join, dirname, extname } from 'path'; -import { stream } from 'got'; -import { pipeline as pipelineSync } from 'stream'; -import { promisify } from 'util'; -import { createWriteStream } from 'fs'; -import { generate as generateId } from 'shortid'; -import { - docClass, - usePackages, - beginDocument, - endDocument, - section, - subsection, - subsubsection, - bold, - italic, - underline, - divider, - itemize, - enumerate, - item, - image, -} from './templates'; - -const pipeline = promisify(pipelineSync); - -function analyzeForPackageImports(HTMLText) { - const pkgs = []; - - if (HTMLText.includes('\\cfrac')) pkgs.push('amsmath'); - if (HTMLText.includes(' name === 'src').value; - const ext = extname(origPath) || '.jpg'; - const base = autoGenImageNames ? `${generateId()}${ext}` : basename(origPath); - const localPath = resolve(imagesDir, base); - const localLatexPath = join('images', base); - const exists = await pathExists(localPath); - - if (!exists) { - try { - const url = new URL(origPath); - - await ensureDir(imagesDir); - - await pipeline(stream(url.href), createWriteStream(localPath)); - } catch (e) { - if (debug) { - console.debug(`URL: ${origPath}`); - console.debug(e); - } - } - } - - return image(localLatexPath, { - width: imageWidth, - height: imageHeight, - keepRatio: keepImageAspectRatio, - center: centerImages, - }); -} - -function convertPlainText(value, opts) { - const breakReplacement = opts.ignoreBreaks ? '' : '\n\n'; - const cleanText = value - .replace(/(\n|\r)/g, breakReplacement) // Standardize line breaks or remove them - .replace(/\t/g, '') // Remove tabs - .replace(/(? bold(t)); - case 'i': - return convertRichText(n, opts).then((t) => italic(t)); - case 'u': - return convertRichText(n, opts).then((t) => underline(t)); - case 'br': - return opts.ignoreBreaks ? ' ' : '\n\n'; - case 'span': - return convertRichText(n, opts); - case '#text': - return convertPlainText(n.value, opts); - default: - return ''; - } -} - -async function convertRichText(node, opts) { - if (node.childNodes && node.childNodes.length > 0) { - const converted = await Promise.all(node.childNodes.map((n) => convertRichTextSingle(n, opts))); - return converted.join(''); - } - - return convertRichTextSingle(node, opts); -} - -async function convertUnorderedLists({ childNodes }, opts) { - const filtered = await childNodes.filter(({ nodeName }) => nodeName === 'li'); - const texts = await Promise.all( - filtered.map((f) => convert([f], { ...opts, includeDocumentWrapper: false })), - ); - const listItems = texts.map(item); - - return itemize(listItems.join('\n')); -} - -async function convertOrderedLists({ childNodes }, opts) { - const filtered = await childNodes.filter(({ nodeName }) => nodeName === 'li'); - const texts = await Promise.all( - filtered.map((f) => convert([f], { ...opts, includeDocumentWrapper: false })), - ); - const listItems = texts.map(item); - - return enumerate(listItems.join('\n')); -} - -async function convertHeading(node, opts) { - const text = await convertRichText(node, opts); - - switch (node.nodeName) { - case 'h1': - return section(text); - case 'h2': - return subsection(text); - default: - return subsubsection(text); - } -} - -export async function convert( - nodes, - { - autoGenImageNames = true, - includeDocumentWrapper = false, - documentClass = 'article', - includePackages = [], - compilationDir = process.cwd(), - ignoreBreaks = true, - preferDollarInlineMath = false, - skipWrappingEquations = false, - debug = false, - imageWidth, - imageHeight, - keepImageAspectRatio, - centerImages, - title, - includeDate, - author, - } = {}, -) { - const blockedNodes = [ - 'h1', - 'h2', - 'h3', - 'ul', - 'ol', - 'img', - 'hr', - 'div', - 'section', - 'body', - 'html', - 'header', - 'footer', - 'aside', - 'p', - ]; - const doc = []; - const opts = { - compilationDir, - ignoreBreaks, - preferDollarInlineMath, - skipWrappingEquations, - autoGenImageNames, - debug, - imageWidth, - imageHeight, - keepImageAspectRatio, - centerImages, - }; - let tempInlineDoc = []; - - if (includeDocumentWrapper) { - doc.push(docClass(documentClass)); - - if (includePackages.length > 0) doc.push(usePackages(includePackages)); - - doc.push(beginDocument({ title, includeDate, author })); - } - - nodes.forEach(async (n) => { - if (!blockedNodes.includes(n.nodeName)) { - tempInlineDoc.push(convertRichText(n, opts)); - return; - } - - if (tempInlineDoc.length > 0) { - doc.push(Promise.all(tempInlineDoc).then((t) => t.join('').trim())); - tempInlineDoc = []; - } - - switch (n.nodeName) { - case 'h1': - case 'h2': - case 'h3': - doc.push(convertHeading(n, opts)); - break; - case 'ul': - doc.push(convertUnorderedLists(n, opts)); - break; - case 'ol': - doc.push(convertOrderedLists(n, opts)); - break; - case 'img': - doc.push(convertImage(n, opts)); - break; - case 'hr': - doc.push(divider); - break; - case 'div': - case 'section': - case 'body': - case 'html': - case 'header': - case 'footer': - case 'aside': - doc.push( - convert(n.childNodes, { - ...opts, - includeDocumentWrapper: false, - }), - ); - break; - case 'p': - doc.push( - convertRichText(n, opts).then((t) => { - const trimmed = t.trim(); - - // Check if text is only an equation. If so, switch \( \) & $ $, for \[ \] - if ( - !opts.skipWrappingEquations && - trimmed.match(/^(\$|\\\()/) && - trimmed.match(/(\\\)|\$)$/) - ) { - const rewrapped = trimmed.replace(/^(\$|\\\()/, '\\[').replace(/(\\\)|\$)$/, '\\]'); - - // TODO: Move all of this into the above regex check - if (!rewrapped.includes('$')) return rewrapped; - } - - return trimmed; - }), - ); - break; - default: - } - }); - - // Insert any left over inline nodes - if (tempInlineDoc.length > 0) { - doc.push(Promise.all(tempInlineDoc).then((t) => t.join('').trim())); - } - - // Add document wrapper if configuration is set - if (includeDocumentWrapper) doc.push(endDocument); - - const converted = await Promise.all(doc); - - return converted.filter(Boolean).join('\n\n'); -} - -export async function convertText(data, options = {}) { - const root = await parseFragment(data); - - return convert(root.childNodes, { - ...options, - includePackages: options.includePackages || analyzeForPackageImports(data), - }); -} - -export async function convertFile(filepath, { outputFilepath = filepath, ...options } = {}) { - const data = await readFile(filepath, 'utf-8'); - const processed = await convertText(data, { includeDocumentWrapper: true, ...options }); - - await exportFile(processed, outputFilepath, dirname(filepath)); -} diff --git a/src/helpers/convert-element.mts b/src/helpers/convert-element.mts new file mode 100644 index 0000000..6cf71cc --- /dev/null +++ b/src/helpers/convert-element.mts @@ -0,0 +1,64 @@ +import type { ChildNode, ConvertElementOptions, ElementNode } from '../types.mts'; +import { convertInlineElement } from './convert-inline-element.mts'; +import * as Template from '../templates.mts'; +import { convertUnorderedList } from './convert-unordered-list.mts'; +import { convertOrderedList } from './convert-ordered-list.mts'; +import { convertImage } from './convert-image.mts'; +import { convertHeading } from './convert-heading.mts'; +import { convertParagraph } from './convert-paragraph.mts'; +import { convertTable } from './convert-table.mts'; + +export async function convertElement( + node: ChildNode, + options?: ConvertElementOptions, +): Promise { + if (!node?.nodeName) return null; + + switch (node.nodeName) { + case 'main': + case 'div': + case 'section': + case 'body': + case 'html': + case 'header': + case 'footer': + case 'aside': { + if ('childNodes' in node && node.childNodes.length > 0) { + const nestedBlocks = await Promise.all( + node.childNodes.map((n) => convertElement(n, options)), + ); + + return nestedBlocks.filter(Boolean).join(Template.blockSeperator); + } + + return null; + } + case 'ul': + return convertUnorderedList(node, options); + case 'ol': + return convertOrderedList(node, options); + case 'img': + return convertImage(node, options); + case 'hr': + return Template.divider(); + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + return convertHeading(node, options); + case 'p': + return convertParagraph(node, options); + case 'table': { + if (node.childNodes.length === 0) return null; + + // A tbody is always added even when missing from the original html + return convertTable(node?.childNodes[0] as ElementNode, options); + } + case 'code': + return Template.sourceCode(convertInlineElement(node, options).trim()); + default: + return convertInlineElement(node, options); + } +} diff --git a/src/helpers/convert-file.mts b/src/helpers/convert-file.mts new file mode 100644 index 0000000..97b1893 --- /dev/null +++ b/src/helpers/convert-file.mts @@ -0,0 +1,18 @@ +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { dirname, extname } from 'node:path'; +import { convertText } from './convert-text.mts'; +import type { ConvertFileOptions } from '../types.mts'; + +export async function convertFile( + filePath: string, + { outputFilePath = filePath, includeDocumentWrapper = true, ...options }: ConvertFileOptions, +): Promise { + const data = await readFile(filePath, 'utf-8'); + const processed = await convertText(data, { ...options, includeDocumentWrapper }); + const directory = dirname(outputFilePath); + const cleanedOutputFilePath = outputFilePath.replace(extname(outputFilePath), '.tex'); + + await mkdir(directory, { recursive: true }); + + return writeFile(cleanedOutputFilePath, processed); +} diff --git a/src/helpers/convert-heading.mts b/src/helpers/convert-heading.mts new file mode 100644 index 0000000..53a0d1b --- /dev/null +++ b/src/helpers/convert-heading.mts @@ -0,0 +1,16 @@ +import { convertInlineElement } from './convert-inline-element.mts'; +import * as Template from '../templates.mts'; +import type { ConvertOptions, ElementNode } from '../types.mts'; + +export function convertHeading(node: ElementNode, options: ConvertOptions = {}): string { + const text = convertInlineElement(node, options); + + switch (node.nodeName) { + case 'h1': + return Template.section(text); + case 'h2': + return Template.subsection(text); + default: + return Template.subsubsection(text); + } +} diff --git a/src/helpers/convert-image.mts b/src/helpers/convert-image.mts new file mode 100644 index 0000000..4ba7c36 --- /dev/null +++ b/src/helpers/convert-image.mts @@ -0,0 +1,58 @@ +import { nanoid as generateId } from 'nanoid'; +import { createWriteStream } from 'node:fs'; +import { mkdir, stat } from 'node:fs/promises'; +import { Readable } from 'node:stream'; +import type { ReadableStream } from 'node:stream/web'; +import { finished } from 'node:stream/promises'; +import { basename, extname, join, resolve } from 'node:path'; +import * as Template from '../templates.mts'; +import type { Attribute, ConvertImageOptions, ElementNode } from '../types.mts'; + +export async function convertImage( + node: ElementNode, + { + compilationDir = process.cwd(), + autogenImageNames = false, + debug = false, + imageWidth, + imageHeight, + keepImageAspectRatio, + centerImages, + } = {} as ConvertImageOptions, +): Promise { + const origPath = (node.attrs.find(({ name }) => name === 'src') as Attribute)?.value; + + if (!origPath) return null; + + const imagesDir = resolve(compilationDir, 'images'); + const ext = extname(origPath) || '.jpg'; + const base = autogenImageNames ? `${generateId()}${ext}` : basename(origPath); + const localPath = resolve(imagesDir, base); + const localLatexPath = join('images', base); + + try { + await stat(localPath); + } catch (fsError) { + try { + await mkdir(imagesDir); + + const url = new URL(origPath); + const { body } = await fetch(url.href); + const fileStream = createWriteStream(localPath); + + await finished(Readable.fromWeb(body as ReadableStream).pipe(fileStream)); + } catch (processError) { + if (debug) { + console.debug(`URL: ${origPath}`); + console.debug(processError); + } + } + } + + return Template.image(localLatexPath, { + width: imageWidth, + height: imageHeight, + keepRatio: keepImageAspectRatio, + center: centerImages, + }); +} diff --git a/src/helpers/convert-imports.mts b/src/helpers/convert-imports.mts new file mode 100644 index 0000000..ca138c4 --- /dev/null +++ b/src/helpers/convert-imports.mts @@ -0,0 +1,12 @@ +export function convertPackageImports(HTMLText: string): string[] { + const pkgs: string[] = []; + + if (HTMLText.includes('\\cfrac')) pkgs.push('amsmath'); + if (HTMLText.includes('')) pkgs.push('ulem'); + if (HTMLText.includes('')) pkgs.push('hyperref'); + if (HTMLText.includes('')) pkgs.push('listings'); + + return pkgs; +} diff --git a/src/helpers/convert-inline-element.mts b/src/helpers/convert-inline-element.mts new file mode 100644 index 0000000..ea91558 --- /dev/null +++ b/src/helpers/convert-inline-element.mts @@ -0,0 +1,43 @@ +import { convertPlainText } from './convert-plain-text.mts'; +import * as Template from '../templates.mts'; +import type { Attribute, ChildNode, ConvertInlineElementOptions, TextNode } from '../types.mts'; + +export function convertInlineElement( + node: ChildNode, + { ignoreBreaks = true, ...options }: ConvertInlineElementOptions = {}, +): string { + const opts = { ignoreBreaks, ...options }; + // If this block has children, call fn on its child and obtain its value + const innerText = + 'childNodes' in node && node.childNodes.length > 0 + ? node.childNodes.map((n) => convertInlineElement(n, opts)).join('') + : ''; + + switch (node.nodeName) { + case '#text': + return convertPlainText((node as unknown as TextNode).value, opts); + case 'b': + case 'strong': + return Template.bold(innerText); + case 'i': + case 'em': + return Template.italic(innerText); + case 'u': + return Template.underline(innerText); + case 's': + return Template.strikethrough(innerText); + case 'sub': + return Template.subscript(innerText); + case 'sup': + return Template.superscript(innerText); + case 'br': + return ignoreBreaks ? ' ' : '\n\n'; + case 'a': + return Template.hyperlink( + innerText, + (node.attrs.find(({ name }) => name === 'href') as Attribute).value, + ); + default: + return innerText; + } +} diff --git a/src/helpers/convert-list.mts b/src/helpers/convert-list.mts new file mode 100644 index 0000000..7658eae --- /dev/null +++ b/src/helpers/convert-list.mts @@ -0,0 +1,13 @@ +import { convertElement } from './convert-element.mts'; +import * as Template from '../templates.mts'; +import type { ConvertElementOptions, ElementNode } from '../types.mts'; + +export async function convertList( + node: ElementNode, + options: ConvertElementOptions = {}, +): Promise { + const filtered = node.childNodes.filter(({ nodeName }) => nodeName === 'li'); + const texts = await Promise.all(filtered.map((f) => convertElement(f, options))); + + return texts.map(Template.item).join('\n'); +} diff --git a/src/helpers/convert-ordered-list.mts b/src/helpers/convert-ordered-list.mts new file mode 100644 index 0000000..93d0bd5 --- /dev/null +++ b/src/helpers/convert-ordered-list.mts @@ -0,0 +1,12 @@ +import { convertList } from './convert-list.mts'; +import * as Template from '../templates.mts'; +import type { ConvertOptions, ElementNode } from '../types.mts'; + +export async function convertOrderedList( + node: ElementNode, + options: ConvertOptions = {}, +): Promise { + const list = await convertList(node, options); + + return Template.enumerate(list); +} diff --git a/src/helpers/convert-paragraph.mts b/src/helpers/convert-paragraph.mts new file mode 100644 index 0000000..b68ef6a --- /dev/null +++ b/src/helpers/convert-paragraph.mts @@ -0,0 +1,29 @@ +import { convertInlineElement } from './convert-inline-element.mts'; +import * as Template from '../templates.mts'; +import type { + ConvertInlineElementOptions, + ConvertParagraphOptions, + ElementNode, +} from '../types.mts'; + +export function convertParagraph( + node: ElementNode, + options?: ConvertParagraphOptions & ConvertInlineElementOptions, +): string { + const convertedInlineText = convertInlineElement(node, options); + const trimmed = convertedInlineText.trim(); + + // Check if text is only an equation. If so, switch \( \) & $ $, for \[ \] + if ( + !options?.skipWrappingEquations && + trimmed.match(/^(\$|\\\()/) && + trimmed.match(/(\\\)|\$)$/) + ) { + const rewrapped = Template.wrappedMath(trimmed); + + // TODO: Move all of this into the above regex check + if (!rewrapped.includes('$')) return rewrapped; + } + + return trimmed; +} diff --git a/src/helpers/convert-plain-text.mts b/src/helpers/convert-plain-text.mts new file mode 100644 index 0000000..caf3728 --- /dev/null +++ b/src/helpers/convert-plain-text.mts @@ -0,0 +1,22 @@ +import { decodeHTML } from 'entities'; +import { ConvertInlineElementOptions } from '../types.mts'; +import * as Template from '../templates.mts'; + +export function convertPlainText( + inputText: string, + { ignoreBreaks = true, preferDollarInlineMath = false }: ConvertInlineElementOptions = {}, +): string { + const breakReplacement = ignoreBreaks ? '' : '\n\n'; + const cleanText = inputText + .replace(/(\n|\r)+/g, '\n') // Standardize line breaks + .replace(/\n/g, breakReplacement) // Standardize through double breaks or remove them + .replace(/\t/g, '') // Remove tabs + // .replace(/\\(?!\\|%|&|_|\$|#|\{|\}|~|\^|<|>|"|\|)/g, '\\textbackslash{}') + .replace(/(\\)([%&#~<>|])|([%&#~<>|])/g, Template.latexSpecialCharacter); + // Ideally, we would check for all special characters, e.g., /(\\)([%&_$#{}~^<>|"])|([%&_$#{}~^<>|"])/g + // However, we are currently allowing equations to be written in the HTML file. + + const decodedText = decodeHTML(cleanText); + + return preferDollarInlineMath ? Template.inlineMath(decodedText) : decodedText; +} diff --git a/src/helpers/convert-table-row.mts b/src/helpers/convert-table-row.mts new file mode 100644 index 0000000..812d3ed --- /dev/null +++ b/src/helpers/convert-table-row.mts @@ -0,0 +1,12 @@ +import { convertInlineElement } from './convert-inline-element.mts'; +import type { ConvertOptions, ElementNode } from '../types.mts'; + +export function convertTableRow(node: ElementNode, options: ConvertOptions = {}): string { + const cells: ElementNode[] = Array.from(node.childNodes).filter( + (n) => n.nodeName === 'td' || n.nodeName === 'th', + ) as ElementNode[]; + const processedCells = cells.map((cell) => convertInlineElement(cell, options)); + + // LaTeX column separator & line end + return `${processedCells.join(' & ')} \\\\\n`; +} diff --git a/src/helpers/convert-table.mts b/src/helpers/convert-table.mts new file mode 100644 index 0000000..f8b7bed --- /dev/null +++ b/src/helpers/convert-table.mts @@ -0,0 +1,13 @@ +import { convertTableRow } from './convert-table-row.mts'; +import type { ConvertOptions, ElementNode } from '../types.mts'; + +export function convertTable(node: ElementNode, options: ConvertOptions = {}): string { + const rows = Array.from(node.childNodes).filter((n) => n.nodeName === 'tr'); + const processedRows = rows.map((row: ElementNode) => convertTableRow(row, options)); + + return ( + `\\begin{tabular}{|${'c|'.repeat(processedRows[0].split('&').length)}}\n` + + `\t\\hline\n\t${processedRows.join('\t\\hline\n\t')}\t\\hline\n` + + `\\end{tabular}` + ); +} diff --git a/src/helpers/convert-text.mts b/src/helpers/convert-text.mts new file mode 100644 index 0000000..35deea8 --- /dev/null +++ b/src/helpers/convert-text.mts @@ -0,0 +1,46 @@ +import { parseFragment } from 'parse5'; +import * as Template from '../templates.mts'; +import type { ConvertOptions } from '../types.mts'; +import { convertElement } from './convert-element.mts'; +import { convertPackageImports } from './convert-imports.mts'; + +export async function convertText( + htmlString: string, + { + includeDocumentWrapper = false, + documentClass = 'article', + includePackages = [], + includeDate = false, + title, + author, + ...options + }: ConvertOptions = {}, +): Promise { + const root = parseFragment(htmlString); + const doc: (Promise | string | null)[] = []; + + if (includeDocumentWrapper) { + doc.push(Template.docClass(documentClass)); + + const packageImports = + includePackages.length > 0 ? includePackages : convertPackageImports(htmlString); + + if (packageImports.length > 0) doc.push(Template.usePackages(packageImports)); + + doc.push(Template.beginDocument({ title, includeDate, author })); + } + + // Convert children + const convertedElements = await Promise.all( + root.childNodes.map((n) => convertElement(n, options)), + ); + + doc.push(...convertedElements.filter(Boolean)); + + // Add document wrapper if configuration is set + if (includeDocumentWrapper) doc.push(Template.endDocument()); + + const converted = await Promise.all(doc); + + return converted.join(Template.blockSeperator); +} diff --git a/src/helpers/convert-unordered-list.mts b/src/helpers/convert-unordered-list.mts new file mode 100644 index 0000000..647893c --- /dev/null +++ b/src/helpers/convert-unordered-list.mts @@ -0,0 +1,12 @@ +import { convertList } from './convert-list.mts'; +import * as Template from '../templates.mts'; +import type { ConvertOptions, ElementNode } from '../types.mts'; + +export async function convertUnorderedList( + node: ElementNode, + options: ConvertOptions = {}, +): Promise { + const list = await convertList(node, options); + + return Template.itemize(list); +} diff --git a/src/helpers/index.mts b/src/helpers/index.mts new file mode 100644 index 0000000..3145888 --- /dev/null +++ b/src/helpers/index.mts @@ -0,0 +1,14 @@ +export * from './convert-imports.mts'; +export * from './convert-file.mts'; +export * from './convert-element.mts'; +export * from './convert-inline-element.mts'; +export * from './convert-heading.mts'; +export * from './convert-image.mts'; +export * from './convert-list.mts'; +export * from './convert-ordered-list.mts'; +export * from './convert-unordered-list.mts'; +export * from './convert-paragraph.mts'; +export * from './convert-plain-text.mts'; +export * from './convert-table-row.mts'; +export * from './convert-table.mts'; +export * from './convert-text.mts'; diff --git a/src/index-bin.mts b/src/index-bin.mts new file mode 100644 index 0000000..93ee5a8 --- /dev/null +++ b/src/index-bin.mts @@ -0,0 +1,103 @@ +#!/usr/bin/env node +import { program } from '@commander-js/extra-typings'; +import { readFileSync } from 'node:fs'; +import { convertFile } from './helpers/convert-file.mts'; + +const pkgJSON = JSON.parse(readFileSync('../package.json').toString()) as Record; + +// Add default settings +program + .name('html-to-latex') + .version(pkgJSON.version) + .command('convert-file') + .description('Converts a html file to a latex file') + .argument('', 'The path to your html file') + .option('-ofp --output-file-path ', 'The output path to your latex file') + .option( + '-ib --ignore-breaks', + 'Instead of replacing `
` with //, ending the line, a simple space character is inserted instead.', + true, + ) + .option('-dm --prefer-dollar-inline-math', 'Replace `(` and `)` with `$`.', false) + .option( + '-swe --skip-wrapping-equations', + 'Is an equation is defined in a `p` tag without any other content besides that equation, it will automatically be wrapped in `[` and `]`.', + false, + ) + .option( + '-dw --include-document-wrapper', + 'Adds a document wrapper around the converted text: `documentclass{article} \begin{document} %converted text% end{document}`.', + false, + ) + .option( + '-dc --document-class ', + 'If a document wrapper is added, the document class will be set: `documentclass{article}`.', + 'article', + ) + .option( + '-ip --include-packages ', + 'If a document wrapper is added, a list of used packages will be added via: `\\usepackage{packagename}`. If nothing is specified, the list of includes packages will be inferred from the html e.g cfrac => amsmath, img => graphicx, \therefore => amssymb', + ) + .option( + '-t --title ', + 'If a document wrapper is added, the title will be set: `\title{Altered Carbon}`.', + ) + .option( + '-a --author <author>', + 'If a document wrapper is added, the author will be set: `author{Takashi Kovacs}`.', + ) + .option( + '-d --include-date', + 'If a document wrapper is added, the current date will be: `date{\today}`.', + false, + ) + .option( + '-cdr --compilation-dir <compilation-dir>', + " If any images need to be downloaded for the latex compilation, they will be places in a 'images' subdirectory inside this directory.", + process.cwd(), + ) + .option( + '-ain --autogen-image-names', + 'To avoid any weird file names, image files that are downloaded are automatically given a random Id with the extension of the original file.', + true, + ) + .option( + '-iw --image-width <image-width>', + 'Allows you to set a image width. This would be in the form normally accepted by latex such as: `2cm`.', + ) + .option( + '-ih --image-height <image-height>', + 'Allows you to set a image height. This would be in the form normally accepted by latex such as: `2cm`.', + ) + .option( + '-kar --keep-image-aspect-ratio', + 'Allows you to maintain the aspect ratio of the image. This also requires either the image width property or image height property to be set.', + false, + ) + .option( + '--debug', + 'Prints error messages when they occur such as when an image cannot be found at the given url.', + false, + ) + .action((inputFilePath, options) => + convertFile(inputFilePath, { + outputFilePath: options.outputFilePath, + ignoreBreaks: options.ignoreBreaks, + preferDollarInlineMath: options.preferDollarInlineMath, + skipWrappingEquations: options.skipWrappingEquations, + includeDocumentWrapper: options.includeDocumentWrapper, + documentClass: options.documentClass, + includePackages: options.includePackages, + title: options.title, + author: options.author, + includeDate: options.includeDate, + compilationDir: options.compilationDir, + autogenImageNames: options.autogenImageNames, + imageWidth: options.imageWidth, + imageHeight: options.imageHeight, + keepImageAspectRatio: options.keepImageAspectRatio, + debug: options.debug, + }), + ); + +program.parse(); diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 5e9961a..0000000 --- a/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export { convertText, convertFile } from './convert'; diff --git a/src/index.mts b/src/index.mts new file mode 100644 index 0000000..578154e --- /dev/null +++ b/src/index.mts @@ -0,0 +1,2 @@ +export { convertText, convertFile } from './helpers/index.mts'; +export type { ConvertOptions, ConvertFileOptions } from './types.mts'; diff --git a/src/templates.js b/src/templates.js deleted file mode 100644 index e0e4030..0000000 --- a/src/templates.js +++ /dev/null @@ -1,56 +0,0 @@ -import { normalizeSafe } from 'upath'; - -export const nls = (text) => `${text}\n`; -export const nlp = (text) => `\n${text}`; - -export const centerblk = (text) => `\\begin{center}\n\t${text}\n\\end{center}`; -export const centering = (text) => `\\centering{${text}}`; - -export const section = (text) => `\\section*{${centering(text)}}`; -export const subsection = (text) => `\\subsection*{${text}}`; -export const subsubsection = (text) => `\\subsubsection*{${text}}`; - -export const bold = (text) => `\\textbf{${text}}`; -export const italic = (text) => `\\textit{${text}}`; -export const underline = (text) => `\\underline{${text}}`; - -export const divider = nls('\\hrule'); - -export const enumerate = (text) => `\\begin{enumerate}\n${text}\n\\end{enumerate}`; -export const itemize = (text) => `\\begin{itemize}\n${text}\n\\end{itemize}`; -export const item = (text) => `\t\\item ${text}`; -export function image(path, { width, height, keepRatio, center } = { center: true }) { - const line = ['\\includegraphics']; - const options = []; - - if (width) options.push(`width=${width}`); - if (height) options.push(`height=${height}`); - if ((width || height) && keepRatio) options.push('keepaspectratio'); - if (options.length) line.push(`[${options.join(',')}]`); - - line.push(`{${normalizeSafe(path)}}`); - - return center ? centerblk(line.join('')) : line.join(''); -} - -export function usePackages(packageNames) { - return nls(packageNames.map((n) => `\\usepackage{${n}}`).join('\n')); -} - -export function beginDocument({ title, includeDate = false, author } = {}) { - const beginningText = []; - - if (title) beginningText.push(`\\title{${title}}`); - if (author) beginningText.push(`\\author{${author}}`); - if (includeDate) beginningText.push(`\\date{\\today}`); - - if (beginningText.length) beginningText.push(nlp(`\\begin{document}`)); - else beginningText.push(`\\begin{document}`); - - if (title) beginningText.push(nlp('\\maketitle')); - - return beginningText.join('\n'); -} - -export const endDocument = nlp('\\end{document}'); -export const docClass = (className) => `\\documentclass{${className}}`; diff --git a/src/templates.mts b/src/templates.mts new file mode 100644 index 0000000..39acabf --- /dev/null +++ b/src/templates.mts @@ -0,0 +1,118 @@ +import { normalizeSafe } from 'upath'; + +export const newLineSuffix = (text: string): string => `${text}\n`; + +export const newLinePrefix = (text: string): string => `\n${text}`; + +export const centerblk = (text: string): string => `\\begin{center}\n\t${text}\n\\end{center}`; + +export const centering = (text: string): string => `\\centering{${text}}`; + +export const section = (text: string): string => `\\section*{${centering(text)}}`; + +export const subsection = (text: string): string => `\\subsection*{${text}}`; + +export const subsubsection = (text: string): string => `\\subsubsection*{${text}}`; + +export const bold = (text: string): string => `\\textbf{${text}}`; + +export const italic = (text: string): string => `\\textit{${text}}`; + +export const underline = (text: string): string => `\\underline{${text}}`; + +export const strikethrough = (text: string): string => `\\sout{${text}}`; + +export const superscript = (text: string): string => `$^{${text}}$`; + +export const subscript = (text: string): string => `$_{${text}}$`; + +export const hyperlink = (text: string, url: string): string => `\\href{${url}}{${text}}`; + +export const divider = () => newLineSuffix('\\hrule'); + +export const enumerate = (text: string): string => `\\begin{enumerate}\n${text}\n\\end{enumerate}`; + +export const itemize = (text: string): string => `\\begin{itemize}\n${text}\n\\end{itemize}`; + +export const item = (text: string): string => `\t\\item ${text}`; + +export const inlineMath = (text: string): string => text.replace(/\\\(|\\\)/g, '$'); + +export const sourceCode = (text: string): string => + `\\begin{lstlisting}\n${text}\n\\end{lstlisting}`; + +export const wrappedMath = (text: string): string => + text.replace(/^(\$|\\\()/, '\\[').replace(/(\\\)|\$)$/, '\\]'); + +export function image( + filePath: string, + { + width, + height, + keepRatio, + center = true, + }: { width?: string; height?: string; keepRatio?: boolean; center?: boolean } = {}, +): string { + const line = ['\\includegraphics']; + const options: string[] = []; + + if (width) options.push(`width=${width}`); + if (height) options.push(`height=${height}`); + if ((width || height) && keepRatio) options.push('keepaspectratio'); + if (options.length) line.push(`[${options.join(',')}]`); + + line.push(`{${normalizeSafe(filePath)}}`); + + return center ? centerblk(line.join('')) : line.join(''); +} + +export function usePackages(packageNames: string[]): string { + return packageNames.map((n) => `\\usepackage{${n}}`).join('\n'); +} + +export function beginDocument({ + title, + author, + includeDate, +}: { + title?: string; + author?: string; + includeDate?: boolean; +}): string { + const beginningText: string[] = []; + + if (title) beginningText.push(`\\title{${title}}`); + if (author) beginningText.push(`\\author{${author}}`); + if (includeDate) beginningText.push(`\\date{\\today}`); + + if (beginningText.length) beginningText.push(newLinePrefix(`\\begin{document}`)); + else beginningText.push(`\\begin{document}`); + + if (title) beginningText.push(newLinePrefix('\\maketitle')); + + return newLineSuffix(beginningText.join('\n')); +} + +export const endDocument = () => newLinePrefix('\\end{document}'); + +export const docClass = (className: string): string => `\\documentclass{${className}}`; + +export const latexSpecialCharacter = (specialCharacter: string): string => { + const latexSpecialCharsMap: Record<string, string> = { + '\\': '\\textbackslash{}', + '{': '\\{', + '}': '\\}', + '%': '\\%', + $: '\\$', + '&': '\\&', + '#': '\\#', + '^': '\\^{}', + _: '\\_', + '~': '\\textasciitilde{}', + '|': '\\textbar{}', + }; + + return latexSpecialCharsMap[specialCharacter] || specialCharacter; +}; + +export const blockSeperator = '\n\n'; diff --git a/src/types.mts b/src/types.mts new file mode 100644 index 0000000..88ef624 --- /dev/null +++ b/src/types.mts @@ -0,0 +1,50 @@ +import type { DefaultTreeAdapterMap, Token } from 'parse5'; + +export type ConvertDocumentOptions = { + includePackages?: string[]; + includeDocumentWrapper?: boolean; + documentClass?: string; + title?: string; + author?: string; + includeDate?: boolean; +}; + +export type ConvertInlineElementOptions = { + preferDollarInlineMath?: boolean; + ignoreBreaks?: boolean; +}; + +export type ConvertImageOptions = { + compilationDir?: string; + autogenImageNames?: boolean; + debug?: boolean; + imageWidth?: string; + imageHeight?: string; + keepImageAspectRatio?: boolean; + centerImages?: boolean; +}; + +export type ConvertParagraphOptions = { + skipWrappingEquations?: boolean; +}; + +export type ConvertElementOptions = ConvertInlineElementOptions & + ConvertImageOptions & + ConvertParagraphOptions; + +export type ConvertOptions = ConvertDocumentOptions & + ConvertInlineElementOptions & + ConvertImageOptions & + ConvertParagraphOptions; + +export type ConvertFileOptions = ConvertOptions & { + outputFilePath?: string; +}; + +export type ElementNode = DefaultTreeAdapterMap['element']; + +export type TextNode = DefaultTreeAdapterMap['textNode']; + +export type ChildNode = DefaultTreeAdapterMap['childNode']; + +export type Attribute = Token.Attribute; diff --git a/test/test-cases/2/index.html b/test/assets/samples/nested.html similarity index 100% rename from test/test-cases/2/index.html rename to test/assets/samples/nested.html diff --git a/test/test-cases/3/index.html b/test/test-cases/3/index.html deleted file mode 100644 index fd17a0e..0000000 --- a/test/test-cases/3/index.html +++ /dev/null @@ -1,3 +0,0 @@ -Three concentric metal shells \(A,{\rm{ }}B\) and \(C\) of respective radii \(a,{\rm{ }}b\) and \(c\) \((a < b < c)\) have surface charge densities \( + \sigma , - \sigma \) and \( + \sigma \) respectively. The potential of shell \({\rm{B}}\) is: <br> <img src="images/image1.png"> - -Net potential at \({\rm{B}}\) is due to superposition of plotential due to all shells.<br>\({V_B} = {V_{B(I)}} + {V_{B(II)}} + {V_{B(III)}}\)<br>\( = \cfrac{{K4\pi {a^2}\sigma }}{b} + \cfrac{{K4\pi {b^2}( - \sigma )}}{b} + \cfrac{{K4\pi {c^2}(\sigma )}}{c}\)<br>Required potential of b<br>\( = \cfrac{{\sigma {a^2}}}{{{\varepsilon _0}b}} - \cfrac{{\sigma {b^2}}}{{{\varepsilon _0}b}} + \cfrac{{\sigma {c^2}}}{{{\varepsilon _0}c}}\)<br>\( = \cfrac{\sigma }{{{\varepsilon _0}}}\left( {\cfrac{{{a^2} - {b^2}}}{b} + c} \right)\) \ No newline at end of file diff --git a/test/test-cases/3/output.tex b/test/test-cases/3/output.tex deleted file mode 100644 index fa6cf20..0000000 --- a/test/test-cases/3/output.tex +++ /dev/null @@ -1,28 +0,0 @@ -\documentclass{article} - -\usepackage{amsmath} -\usepackage{graphicx} - - -\begin{document} - -Three concentric metal shells \(A,{\rm{ }}B\) and \(C\) of respective radii \(a,{\rm{ }}b\) and \(c\) \((a < b < c)\) have surface charge densities \( + \sigma , - \sigma \) and \( + \sigma \) respectively. The potential of shell \({\rm{B}}\) is: - -\begin{center} - \includegraphics{images/image2.png} -\end{center} - -Net potential at \({\rm{B}}\) is due to superposition of plotential due to all shells. - -\({V_B} = {V_{B(I)}} + {V_{B(II)}} + {V_{B(III)}}\) - -\( = \cfrac{{K4\pi {a^2}\sigma }}{b} + \cfrac{{K4\pi {b^2}( - \sigma )}}{b} + \cfrac{{K4\pi {c^2}(\sigma )}}{c}\) - -Required potential of b - -\( = \cfrac{{\sigma {a^2}}}{{{\varepsilon _0}b}} - \cfrac{{\sigma {b^2}}}{{{\varepsilon _0}b}} + \cfrac{{\sigma {c^2}}}{{{\varepsilon _0}c}}\) - -\( = \cfrac{\sigma }{{{\varepsilon _0}}}\left( {\cfrac{{{a^2} - {b^2}}}{b} + c} \right)\) - - -\end{document} \ No newline at end of file diff --git a/test/unit/convert.js b/test/unit/convert.js deleted file mode 100644 index 755c3cc..0000000 --- a/test/unit/convert.js +++ /dev/null @@ -1,479 +0,0 @@ -import { directory } from 'tempy'; -import { pathExists, remove, readFile } from 'fs-extra'; -import { resolve } from 'path'; -import ShortId from 'shortid'; -import { convertText, exportFile, convertFile } from '../../src/convert'; - -describe('exportFile', () => { - let dir; - - beforeEach(() => { - dir = directory(); - }); - - afterEach(async () => { - await remove(dir); - }); - - it('should export latex file', async () => { - await exportFile('testing', 'test', dir); - - const exists = await pathExists(resolve(dir, 'test.tex')); - - expect(exists).toBeTruthy(); - }); -}); - -describe('convertText', () => { - describe('Document wrapper', () => { - it('should insert the basic document wrapper and default document class of article', async () => { - const html = `<body></body>`; - const tex = await convertText(html, { includeDocumentWrapper: true }); - - expect(tex).toBe('\\documentclass{article}\n\n\\begin{document}\n\n\n\\end{document}'); - }); - - it('should insert the basic document heading with author', async () => { - const html = `<body></body>`; - const tex = await convertText(html, { includeDocumentWrapper: true, author: 'Takashi' }); - - expect(tex).toBe( - '\\documentclass{article}\n\n\\author{Takashi}\n\n\\begin{document}\n\n\n\\end{document}', - ); - }); - - it('should insert the basic document heading with title', async () => { - const html = `<body></body>`; - const tex = await convertText(html, { - includeDocumentWrapper: true, - title: 'Altered Carbon', - }); - - expect(tex).toBe( - '\\documentclass{article}\n\n\\title{Altered Carbon}\n\n\\begin{document}\n\n\\maketitle\n\n\n\\end{document}', - ); - }); - - it('should insert the basic document heading with date', async () => { - const html = `<body></body>`; - const tex = await convertText(html, { includeDocumentWrapper: true, includeDate: true }); - - expect(tex).toBe( - '\\documentclass{article}\n\n\\date{\\today}\n\n\\begin{document}\n\n\n\\end{document}', - ); - }); - }); - - describe('Converting embedded sectioning tags', () => { - it('should properly convert section tags', async () => { - const html = `<body><section>Test</section></body>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - - it('should properly convert aside tags', async () => { - const html = `<body><aside>Test</aside></body>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - - it('should properly convert div tags', async () => { - const html = `<body><div>Test</div></body>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - - it('should properly convert html tags', async () => { - const html = `<html><body>Test</body></html>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - - it('should properly convert header tags', async () => { - const html = `<body><header>Test</header></body>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - - it('should properly convert footer tags', async () => { - const html = `<body><footer>Test</footer></body>`; - const tex = await convertText(html); - - expect(tex).toBe('Test'); - }); - }); - - describe('Converting general text', () => { - it('should convert simple text tag with bold `b` styling', async () => { - const html = `<p>Styled <b>Text</b></p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled \\textbf{Text}'); - }); - - it('should convert simple text tag with bold `strong` styling', async () => { - const html = `<p>Styled <b>Text</b></p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled \\textbf{Text}'); - }); - - it('should convert simple text tag with italics styling', async () => { - const html = `<p>Styled <i>Text</i></p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled \\textit{Text}'); - }); - - it('should convert simple text tag with underline styling', async () => { - const html = `<p>Styled <u>Text</u></p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled \\underline{Text}'); - }); - - it('should convert text tag with span nesting', async () => { - const html = `<p>Styled <span>Text</span></p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled Text'); - }); - - it('should ignore `\t`', async () => { - const html = `<p>Styled\tText</p>`; - const tex = await convertText(html); - - expect(tex).toBe('StyledText'); - }); - - it('should escape `%`', async () => { - const html = `<p>Styled%Text</p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled\\%Text'); - }); - - it('should not escape `%` if its already escaped', async () => { - const html = `<p>Styled\\%Text</p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled\\%Text'); - }); - }); - - describe('Converting text with different types of breaks', () => { - it('should convert simple `p` tag text with `br` tags. These will be ignored by default', async () => { - const html = `<p>Styled<br/>Text</p>`; - const tex = await convertText(html); - - expect(tex).toBe('Styled Text'); - }); - - it('should convert simple `p` tag text with `br` tags and the ignoreBreaks argument set to false', async () => { - const html = `<p>Styled<br/>Text</p>`; - const tex = await convertText(html, { ignoreBreaks: false }); - - expect(tex).toBe('Styled\n\nText'); - }); - - it('should convert simple text with `\n` and the ignoreBreaks argument set to false', async () => { - const html = `<p>Styled\nText</p>`; - const tex = await convertText(html, { ignoreBreaks: false }); - - expect(tex).toBe('Styled\n\nText'); - }); - - it('should convert simple text with `\r` and the ignoreBreaks argument set to false', async () => { - const html = `<p>Styled\rText</p>`; - const tex = await convertText(html, { ignoreBreaks: false }); - - expect(tex).toBe('Styled\n\nText'); - }); - }); - - describe('Unwrapped content', () => { - it('should convert simple text with `br` tags and the ignoreBreaks argument set to false', async () => { - const html = `Styled<br/>Text`; - const tex = await convertText(html, { ignoreBreaks: false }); - - expect(tex).toBe('Styled\n\nText'); - }); - - it('should convert complex text with `br` tags and the ignoreBreaks argument set to false', async () => { - const html = `Three concentric metal shells<br/>More text here.<p> Inner p tag </p>`; - const tex = await convertText(html, { ignoreBreaks: false }); - - expect(tex).toBe('Three concentric metal shells\n\nMore text here.\n\nInner p tag'); - }); - }); - - describe('Converting text with equations', () => { - it('should convert eq wrappers p tags with only an eq to use the \\[ wrapper instead of \\(', async () => { - const html = `<p>\\(x = 5\\Omega\\)</p>`; - const tex = await convertText(html); - - expect(tex).toBe('\\[x = 5\\Omega\\]'); - }); - - it('should convert p tags with only an eq to use the \\[ wrapper instead of $', async () => { - const html = `<p>$x = 5\\Omega$</p>`; - const tex = await convertText(html); - - expect(tex).toBe('\\[x = 5\\Omega\\]'); - }); - - it('should not convert p tags with only an eq to use the \\[ wrapper instead of \\( if skipWrappingEquations is true', async () => { - const html = `<p>\\(x = 5\\Omega\\)</p>`; - const tex = await convertText(html, { skipWrappingEquations: true }); - - expect(tex).toBe('\\(x = 5\\Omega\\)'); - }); - - it('should not convert p tags with only an eq to use the \\[ wrapper instead of $ if skipWrappingEquations is true', async () => { - const html = `<p>$x = 5\\Omega$</p>`; - const tex = await convertText(html, { skipWrappingEquations: true }); - - expect(tex).toBe('$x = 5\\Omega$'); - }); - - it('should not modify eq wrappers in p tags with an eq and other content', async () => { - const html = `<p>Some content $x = 5\\Omega$</p>`; - const tex = await convertText(html); - - expect(tex).toBe('Some content $x = 5\\Omega$'); - }); - - it('should prefer $ eq wrappers if configuration is given', async () => { - const html = `<p>Some content \\(x = 5\\Omega\\)</p>`; - const tex = await convertText(html, { preferDollarInlineMath: true }); - - expect(tex).toBe('Some content $x = 5\\Omega$'); - }); - - it('should handle eqs deep within text without tag wrapping', async () => { - const html = - 'This is some plain text \\(A,{\\rm{ }}B\\) and \\(C\\) with random equations \\(a,{\\rm{ }}b\\) and \\(c\\) \\((a < b < c)\\)'; - const tex = await convertText(html, { preferDollarInlineMath: true }); - - expect(tex).toBe( - 'This is some plain text $A,{\\rm{ }}B$ and $C$ with random equations $a,{\\rm{ }}b$ and $c$ $(a < b < c)$', - ); - }); - }); - - describe('Converting H tags', () => { - it('should convert simple h tag without special chars', async () => { - const html = `<h1>Heading</h1>`; - const tex = await convertText(html); - - expect(tex).toBe('\\section*{\\centering{Heading}}'); - }); - - it('should convert simple h2 tag without special chars', async () => { - const html = `<h2>Heading</h2>`; - const tex = await convertText(html); - - expect(tex).toBe('\\subsection*{Heading}'); - }); - - it('should convert simple h3 tag without special chars', async () => { - const html = `<h3>Heading</h3>`; - const tex = await convertText(html); - - expect(tex).toBe('\\subsubsection*{Heading}'); - }); - - it('should convert simple h tag with special chars', async () => { - const html = `<h1>Heading's</h1>`; - const tex = await convertText(html); - - expect(tex).toBe("\\section*{\\centering{Heading's}}"); - }); - - it('should convert h tag with embedded css', async () => { - const html = `<h1 style="margin:0px">Heading's</h1>`; - const tex = await convertText(html); - - expect(tex).toBe("\\section*{\\centering{Heading's}}"); - }); - - it('should convert h tag with embedded css and special characters', async () => { - const html = - '<h1 style="margin-left:0in; margin-right:0in; text-align:center"><u><strong>Newton's Laws of Motion</strong></u></h1>'; - const tex = await convertText(html); - - expect(tex).toBe("\\section*{\\centering{\\underline{\\textbf{Newton's Laws of Motion}}}}"); - }); - }); - - describe('Converting divider tags', () => { - it('should convert simple divider tag', async () => { - const html = `<p>Text</p><hr/><p>More Text</p>`; - const tex = await convertText(html); - - expect(tex).toBe('Text\n\n\\hrule\n\n\nMore Text'); - }); - }); - - describe('Converting img tags', () => { - it('should convert simple img tag', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { autoGenImageNames: false }); - - expect(tex).toBe('\\begin{center}\n\t\\includegraphics{images/image.png}\n\\end{center}'); - }); - - it('should convert wrapped img tag', async () => { - const spy = jest.spyOn(ShortId, 'generate'); - spy.mockImplementation(() => 'image2'); - - const html = `<p><img src="image.png"/></p>`; - const tex = await convertText(html); - - expect(tex).toBe('\\begin{center}\n\t\\includegraphics{images/image2.png}\n\\end{center}'); - - spy.mockClear(); - }); - - it('should default to a jpg extension when converting img tag with a image url without a extension', async () => { - const spy = jest.spyOn(ShortId, 'generate'); - spy.mockImplementation(() => 'image2'); - - const html = `<p><img src="image"/></p>`; - const tex = await convertText(html); - - expect(tex).toBe('\\begin{center}\n\t\\includegraphics{images/image2.jpg}\n\\end{center}'); - - spy.mockClear(); - }); - - it('should add width restrictions when given', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { autoGenImageNames: false, imageWidth: '2cm' }); - - expect(tex).toBe( - '\\begin{center}\n\t\\includegraphics[width=2cm]{images/image.png}\n\\end{center}', - ); - }); - - it('should add height restrictions when given', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { autoGenImageNames: false, imageHeight: '2cm' }); - - expect(tex).toBe( - '\\begin{center}\n\t\\includegraphics[height=2cm]{images/image.png}\n\\end{center}', - ); - }); - - it('should keep aspect ratio when given and width or height are restricted', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { - autoGenImageNames: false, - imageHeight: '2cm', - keepImageAspectRatio: true, - }); - - expect(tex).toBe( - '\\begin{center}\n\t\\includegraphics[height=2cm,keepaspectratio]{images/image.png}\n\\end{center}', - ); - }); - - it('should ignore aspect ratio when given if width or height are not restricted', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { autoGenImageNames: false, keepImageAspectRatio: true }); - - expect(tex).toBe('\\begin{center}\n\t\\includegraphics{images/image.png}\n\\end{center}'); - }); - - it('should not center the image', async () => { - const html = `<img src="image.png"/>`; - const tex = await convertText(html, { autoGenImageNames: false, centerImages: false }); - - expect(tex).toBe('\\includegraphics{images/image.png}'); - }); - }); - - describe('Converting list tags', () => { - it('should convert simple ul list tag', async () => { - const html = `<ul><li>Angle reaction</li></ul>`; - const tex = await convertText(html); - - expect(tex).toBe('\\begin{itemize}\n\t\\item Angle reaction\n\\end{itemize}'); - }); - - it('should convert simple ol list tag', async () => { - const html = `<ol><li>Angle reaction</li></ol>`; - const tex = await convertText(html); - - expect(tex).toBe('\\begin{enumerate}\n\t\\item Angle reaction\n\\end{enumerate}'); - }); - }); - - describe('Converting with debug flag', () => { - it('should display errors when converting img tag with an inaccessible source url with the debug flag', async () => { - const spy = jest.spyOn(console, 'debug').mockImplementation(); - const html = `<img src="image.png"/>`; - - await convertText(html, { autoGenImageNames: false, debug: true }); - - expect(spy).toBeCalledTimes(2); - - spy.mockRestore(); - }); - - it('should not display errors when converting img tag with an inaccessible source url without the debug flag', async () => { - const spy = jest.spyOn(console, 'debug').mockImplementation(); - const html = `<img src="image.png"/>`; - - await convertText(html, { autoGenImageNames: false }); - - expect(spy).toBeCalledTimes(0); - - spy.mockRestore(); - }); - }); -}); - -describe('convertFile', () => { - describe('Converting mixed tags', () => { - it('should convert text with a mixture of nested tags', async () => { - await convertFile(resolve(__dirname, '../test-cases/2/index.html'), { - includeDocumentWrapper: false, - }); - - const tex = await readFile(resolve(__dirname, '../test-cases/2/index.html.tex'), 'utf-8'); - const text = [ - "\\section*{\\centering{\\underline{\\textbf{Newton's Laws of Motion}}}}", - '', - '\\subsection*{\\textbf{Concept of Forces}}', - '', - 'Some types of forces may be (i) Contact forces, (ii) Non-contact forces \\textbf{Contact forces} involve physical contact between two objects.', - ]; - - expect(tex).toBe(text.join('\n')); - - await remove(resolve(__dirname, '../test-cases/2/index.html.tex')); - }); - }); - - it('should convert text without tag wrapper while ignoring break tags', async () => { - const spy = jest.spyOn(ShortId, 'generate'); - spy.mockImplementation(() => 'image2'); - - await convertFile(resolve(__dirname, '../test-cases/3/index.html'), { ignoreBreaks: false }); - - const tex = await readFile(resolve(__dirname, '../test-cases/3/index.html.tex'), 'utf-8'); - const ref = await readFile(resolve(__dirname, '../test-cases/3/output.tex'), 'utf-8'); - - expect(tex).toBe(ref); - - await remove(resolve(__dirname, '../test-cases/3/index.html.tex')); - - spy.mockClear(); - }); -}); diff --git a/test/unit/helpers/convert-element.mts b/test/unit/helpers/convert-element.mts new file mode 100644 index 0000000..2dab67b --- /dev/null +++ b/test/unit/helpers/convert-element.mts @@ -0,0 +1,236 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import { convertElement } from '../../../src/helpers/convert-element.mts'; +import * as Template from '../../../src/templates.mts'; +import * as convertOrderedListsUtils from '../../../src/helpers/convert-ordered-list.mts'; +import * as convertUnorderedListsUtils from '../../../src/helpers/convert-unordered-list.mts'; +import * as convertImageUtils from '../../../src/helpers/convert-image.mts'; +import * as convertHeadingUtils from '../../../src/helpers/convert-heading.mts'; +import * as convertParagraphUtils from '../../../src/helpers/convert-paragraph.mts'; +import * as convertTableUtils from '../../../src/helpers/convert-table.mts'; +import * as convertInlineElementUtils from '../../../src/helpers/convert-inline-element.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should handle broken nodes', async () => { + const node = parseFragment('<tab src=" />').childNodes[0]; + + const tex = await convertElement(node); + + expect(tex).toBe(null); +}); + +it('should handle empty block elements', async () => { + const node = parseFragment('<div></div>').childNodes[0]; + + const tex = await convertElement(node); + + expect(tex).toBe(null); +}); + +it('should properly convert html tags', async () => { + const node = parseFragment('<html><body>Test</body></html>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should convert a div', async () => { + const node = parseFragment('<div>Test</div>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should convert a nested div', async () => { + const node = parseFragment('<div><div>Hello World!</div></div>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Hello World!'); +}); + +it('should properly convert section tags', async () => { + const node = parseFragment('<body><section>Test</section></body>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should properly convert aside tags', async () => { + const node = parseFragment('<body><aside>Test</aside></body>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should properly convert aside tags', async () => { + const node = parseFragment('<body><footer>Test</footer></body>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should properly convert main tags', async () => { + const node = parseFragment('<body><main>Test</main></body>'); + const tex = await convertElement(node.childNodes[0]); + + expect(tex).toBe('Test'); +}); + +it('should assume unknown elements are inline elements', async () => { + const convertInlineElementSpy = vi.spyOn(convertInlineElementUtils, 'convertInlineElement'); + + const node = parseFragment('<unknown>Text</unknown>').childNodes[0]; + + await convertElement(node); + + expect(convertInlineElementSpy).toHaveBeenCalledWith(node, undefined); +}); + +it('should convert an unknown tag', async () => { + const node = parseFragment('<unknown>Text</unknown>').childNodes[0]; + const tex = await convertElement(node); + + expect(tex).toBe('Text'); +}); + +it('should convert an unknown tag inside text', async () => { + const node = parseFragment('<p>I was born on <time datetime="1000-12-31 12:00">31 Dec</time></p>') + .childNodes[0]; + const tex = await convertElement(node); + + expect(tex).toBe('I was born on 31 Dec'); +}); + +it('should convert horizontal rule', async () => { + const dividerSpy = vi.spyOn(Template, 'divider'); + const node = parseFragment('<hr>').childNodes[0]; + + await convertElement(node); + + expect(dividerSpy).toHaveBeenCalled(); +}); + +it('should convert code tags', async () => { + const templateSpy = vi.spyOn(Template, 'sourceCode'); + const node = parseFragment(`<code>console.log('Hello World!');</code>`).childNodes[0]; + + await convertElement(node); + + expect(templateSpy).toHaveBeenCalledWith(`console.log('Hello World!');`); +}); + +it('should convert heading tags', async () => { + const convertHeadingSpy = vi.spyOn(convertHeadingUtils, 'convertHeading'); + + // H1 + const h1Node = parseFragment('<h1>Heading</h1>').childNodes[0]; + + await convertElement(h1Node, undefined); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h1Node, undefined); + + // H2 + const h2Node = parseFragment('<h2>Heading</h2>').childNodes[0]; + + await convertElement(h2Node); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h2Node, undefined); + + // H3 + const h3Node = parseFragment('<h3>Heading</h3>').childNodes[0]; + + await convertElement(h3Node); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h3Node, undefined); + + // H4 + const h4Node = parseFragment('<h4>Heading</h4>').childNodes[0]; + + await convertElement(h4Node); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h4Node, undefined); + + // H5 + const h5Node = parseFragment('<h5>Heading</h5>').childNodes[0]; + + await convertElement(h5Node); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h5Node, undefined); + + // H6 + const h6Node = parseFragment('<h6>Heading</h6>').childNodes[0]; + + await convertElement(h6Node); + + expect(convertHeadingSpy).toHaveBeenCalledWith(h6Node, undefined); +}); + +it('should convert list tags', async () => { + const convertUnorderedListSpy = vi.spyOn(convertUnorderedListsUtils, 'convertUnorderedList'); + const convertOrderedListSpy = vi.spyOn(convertOrderedListsUtils, 'convertOrderedList'); + + // Unordered List + const unorderedNode = parseFragment('<ul><li>item</li></ul>').childNodes[0]; + + await convertElement(unorderedNode); + + expect(convertUnorderedListSpy).toHaveBeenCalledWith(unorderedNode, undefined); + + // Ordered List + const orderedNode = parseFragment('<ol><li>item</li></ol>').childNodes[0]; + + await convertElement(orderedNode); + + expect(convertOrderedListSpy).toHaveBeenCalledWith(orderedNode, undefined); +}); + +it('should convert image tags', async () => { + const convertImageSpy = vi.spyOn(convertImageUtils, 'convertImage'); + const node = parseFragment('<img/>').childNodes[0]; + + convertImageSpy.mockImplementationOnce(() => Promise.resolve('')); + + await convertElement(node); + + expect(convertImageSpy).toHaveBeenCalledWith(node, undefined); +}); + +it('should convert paragraph tags', async () => { + const convertParagraphSpy = vi.spyOn(convertParagraphUtils, 'convertParagraph'); + const node = parseFragment('<p>Test</p>').childNodes[0]; + + await convertElement(node); + + expect(convertParagraphSpy).toHaveBeenCalledWith(node, undefined); +}); + +it('should convert table tags without inner tbody', async () => { + const convertTableSpy = vi.spyOn(convertTableUtils, 'convertTable'); + const node: ElementNode = parseFragment('<table><tr></tr></table>').childNodes[0] as ElementNode; + + convertTableSpy.mockImplementationOnce(() => ''); + + await convertElement(node); + + expect(convertTableSpy).toHaveBeenCalledWith(node.childNodes[0], undefined); +}); + +it('should convert table tags with inner tbody', async () => { + const convertTableSpy = vi.spyOn(convertTableUtils, 'convertTable'); + const node: ElementNode = parseFragment('<table><tbody><tr></tr></tbody></table>') + .childNodes[0] as ElementNode; + + convertTableSpy.mockImplementationOnce(() => ''); + + await convertElement(node); + + expect(convertTableSpy).toHaveBeenCalledWith(node.childNodes[0], undefined); +}); + +it('should not convert empty tables', async () => { + const node: ElementNode = parseFragment('<table></table>').childNodes[0] as ElementNode; + + const tex = await convertElement(node); + + expect(tex).toBe(null); +}); diff --git a/test/unit/helpers/convert-file.mts b/test/unit/helpers/convert-file.mts new file mode 100644 index 0000000..94fafcc --- /dev/null +++ b/test/unit/helpers/convert-file.mts @@ -0,0 +1,53 @@ +import { expect, test as it, vi, afterAll } from 'vitest'; +import { resolve } from 'node:path'; +import { readFile, rm, mkdtemp, copyFile } from 'node:fs/promises'; +import { convertFile } from '../../../src/helpers/convert-file.mjs'; + +const testTemporaryDirectory = await mkdtemp('test-artifacts'); + +afterAll(async () => { + await rm(testTemporaryDirectory, { recursive: true, force: true }); +}); + +it('should convert text with a mixture of nested tags', async () => { + const outputPath = resolve(testTemporaryDirectory, 'nested.tex'); + + await convertFile(resolve(__dirname, '../../assets/samples/nested.html'), { + includeDocumentWrapper: false, + outputFilePath: outputPath, + }); + + const tex = await readFile(outputPath, 'utf-8'); + const text = [ + "\\section*{\\centering{\\underline{\\textbf{Newton's Laws of Motion}}}}", + '', + '\\subsection*{\\textbf{Concept of Forces}}', + '', + 'Some types of forces may be (i) Contact forces, (ii) Non-contact forces \\textbf{Contact forces} involve physical contact between two objects.', + ]; + + expect(tex).toBe(text.join('\n')); +}); + +it('should output to the source file directory by default', async () => { + const outputPath = resolve(testTemporaryDirectory, 'default-path.tex'); + const originalSourcePath = resolve(__dirname, '../../assets/samples/nested.html'); + const newSourcePath = resolve(testTemporaryDirectory, 'default-path.html'); + + await copyFile(originalSourcePath, newSourcePath); + + await convertFile(newSourcePath, { + includeDocumentWrapper: false, + }); + + const tex = await readFile(outputPath, 'utf-8'); + const text = [ + "\\section*{\\centering{\\underline{\\textbf{Newton's Laws of Motion}}}}", + '', + '\\subsection*{\\textbf{Concept of Forces}}', + '', + 'Some types of forces may be (i) Contact forces, (ii) Non-contact forces \\textbf{Contact forces} involve physical contact between two objects.', + ]; + + expect(tex).toBe(text.join('\n')); +}); diff --git a/test/unit/helpers/convert-heading.mts b/test/unit/helpers/convert-heading.mts new file mode 100644 index 0000000..9de2786 --- /dev/null +++ b/test/unit/helpers/convert-heading.mts @@ -0,0 +1,42 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import * as Template from '../../../src/templates.mts'; +import { convertHeading } from '../../../src/helpers/convert-heading.mts'; +import * as convertInlineUtils from '../../../src/helpers/convert-inline-element.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should convert h1 tags to sections', () => { + const convertInlineElementSpy = vi.spyOn(convertInlineUtils, 'convertInlineElement'); + const templateSpy = vi.spyOn(Template, 'section'); + + const node = parseFragment('<h1>Text</h1>'); + + convertHeading(node.childNodes[0] as ElementNode); + + expect(convertInlineElementSpy).toBeCalledWith(node.childNodes[0], {}); + expect(templateSpy).toBeCalledWith('Text'); +}); + +it('should convert h2 tags to subsections', () => { + const convertInlineElementSpy = vi.spyOn(convertInlineUtils, 'convertInlineElement'); + const templateSpy = vi.spyOn(Template, 'subsection'); + + const node = parseFragment('<h2>Text</h2>'); + + convertHeading(node.childNodes[0] as ElementNode); + + expect(convertInlineElementSpy).toBeCalledWith(node.childNodes[0], {}); + expect(templateSpy).toBeCalledWith('Text'); +}); + +it('should convert h3 tags to subsubsections', () => { + const convertInlineElementSpy = vi.spyOn(convertInlineUtils, 'convertInlineElement'); + const templateSpy = vi.spyOn(Template, 'subsubsection'); + + const node = parseFragment('<h3>Text</h3>'); + + convertHeading(node.childNodes[0] as ElementNode); + + expect(convertInlineElementSpy).toBeCalledWith(node.childNodes[0], {}); + expect(templateSpy).toBeCalledWith('Text'); +}); diff --git a/test/unit/helpers/convert-image.mts b/test/unit/helpers/convert-image.mts new file mode 100644 index 0000000..ee30e39 --- /dev/null +++ b/test/unit/helpers/convert-image.mts @@ -0,0 +1,271 @@ +import { expect, test as it, vi } from 'vitest'; +import { PassThrough, Readable } from 'node:stream'; +import * as FS from 'node:fs'; +import type { WriteStream } from 'node:fs'; +import * as FSp from 'node:fs/promises'; +import { resolve } from 'node:path'; +import * as NanoId from 'nanoid'; +import { convertImage } from '../../../src/helpers/convert-image.mts'; +import type { ElementNode } from '../../../src/types.mts'; +import * as Template from '../../../src/templates.mts'; + +vi.mock('node:fs'); +vi.mock('node:fs/promises'); +vi.mock('nanoid'); + +const mockFetch = vi.fn(); +const mockWritable = new PassThrough(); +const createWriteStreamMock = vi.spyOn(FS, 'createWriteStream'); +const mkdirMock = vi.spyOn(FSp, 'mkdir'); +const statMock = vi.spyOn(FSp, 'stat'); +const nanoIdMock = vi.spyOn(NanoId, 'nanoid'); + +global.fetch = mockFetch; + +it('should generate a latex image template', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + const output = await convertImage(node); + + expect(output).toBe('\\begin{center}\n\t\\includegraphics{images/test.jpg}\n\\end{center}'); +}); + +it('should return the result of the image template function', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const imageTemplateSpy = vi.spyOn(Template, 'image'); + imageTemplateSpy.mockImplementationOnce(() => 'imageTemplate'); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + const output = await convertImage(node); + + expect(output).toBe('imageTemplate'); +}); + +it('should create a images directory if one does not exist', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + const imagesDir = resolve(process.cwd(), 'images'); + + await convertImage(node); + + expect(statMock).toBeCalledWith(resolve(imagesDir, 'test.jpg')); + expect(mkdirMock).toBeCalledWith(imagesDir); +}); + +it('should create a download the image using fetch and stream it to a file', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + + await convertImage(node); + + expect(mockFetch).toBeCalledWith('http://test.com/image.jpg'); + expect(createWriteStreamMock).toBeCalledWith(resolve(process.cwd(), 'images', 'image.jpg')); +}); + +it('should support setting the parent directory for the images directory', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + + await convertImage(node, { compilationDir: 'test-directory' }); + + const imagesDir = resolve('test-directory', 'images'); + + expect(mkdirMock).toBeCalledWith(imagesDir); + expect(createWriteStreamMock).toBeCalledWith(resolve(imagesDir, 'image.jpg')); +}); + +it('should support autogenerated image filenames when saving the file', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + nanoIdMock.mockImplementationOnce(() => 'generatedid'); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + + await convertImage(node, { autogenImageNames: true }); + + const imagesDir = resolve(process.cwd(), 'images'); + + expect(createWriteStreamMock).toBeCalledWith(resolve(imagesDir, 'generatedid.jpg')); +}); + +it('should use a jpg as the default file extension if it cant be infered from the link only when autogenerating file names', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + nanoIdMock.mockImplementationOnce(() => 'generatedid'); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image' }] } as ElementNode; + + await convertImage(node, { autogenImageNames: true }); + + const imagesDir = resolve(process.cwd(), 'images'); + + expect(createWriteStreamMock).toBeCalledWith(resolve(imagesDir, 'generatedid.jpg')); +}); + +it("should use the image's filename by default when saving the file", async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + const imagesDir = resolve(process.cwd(), 'images'); + + await convertImage(node); + + expect(createWriteStreamMock).toBeCalledWith(resolve(imagesDir, 'image.jpg')); +}); + +it('should handle errors that occur while downloading the image', async () => { + mockFetch.mockImplementationOnce(() => { + throw new Error('Fetch Error'); + }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + + const output = await convertImage(node); + + expect(typeof output).toBe('string'); +}); + +it('should output logs if debug flag is passed and an error occurs during the file download', async () => { + const fetchError = new Error('Fetch Error'); + + mockFetch.mockImplementationOnce(() => { + throw fetchError; + }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + statMock.mockImplementationOnce(() => { + throw new Error('File DNE'); + }); + + const consoleMock = vi.spyOn(console, 'debug'); + + const node = { attrs: [{ name: 'src', value: 'http://test.com/image.jpg' }] } as ElementNode; + + await convertImage(node, { debug: true }); + + expect(consoleMock).toHaveBeenCalledWith(fetchError); + expect(consoleMock).toHaveBeenCalledWith('URL: http://test.com/image.jpg'); +}); + +it('should support setting the imageWidth', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const imageTemplateSpy = vi.spyOn(Template, 'image'); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + + await convertImage(node, { + imageWidth: '2cm', + }); + + expect(imageTemplateSpy).toHaveBeenCalledWith('images/test.jpg', { + width: '2cm', + keepRatio: undefined, + center: undefined, + height: undefined, + }); +}); + +it('should support setting the imageHeight', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const imageTemplateSpy = vi.spyOn(Template, 'image'); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + + await convertImage(node, { + imageHeight: '2cm', + }); + + expect(imageTemplateSpy).toHaveBeenCalledWith('images/test.jpg', { + height: '2cm', + keepRatio: undefined, + center: undefined, + width: undefined, + }); +}); + +it('should support setting the keepImageAspectRatio flag', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const imageTemplateSpy = vi.spyOn(Template, 'image'); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + + await convertImage(node, { + keepImageAspectRatio: true, + }); + + expect(imageTemplateSpy).toHaveBeenCalledWith('images/test.jpg', { + keepRatio: true, + height: undefined, + center: undefined, + width: undefined, + }); +}); + +it('should support setting the centerImages flag', async () => { + mockFetch.mockResolvedValue({ body: Readable.from('hello') }); + createWriteStreamMock.mockReturnValueOnce(mockWritable as unknown as WriteStream); + mkdirMock.mockImplementationOnce(() => Promise.resolve('done')); + + const imageTemplateSpy = vi.spyOn(Template, 'image'); + + const node = { attrs: [{ name: 'src', value: 'test.jpg' }] } as ElementNode; + + await convertImage(node, { + centerImages: false, + }); + + expect(imageTemplateSpy).toHaveBeenCalledWith('images/test.jpg', { + center: false, + height: undefined, + keepRatio: undefined, + width: undefined, + }); +}); diff --git a/test/unit/helpers/convert-imports.mts b/test/unit/helpers/convert-imports.mts new file mode 100644 index 0000000..daec2d9 --- /dev/null +++ b/test/unit/helpers/convert-imports.mts @@ -0,0 +1,38 @@ +import { expect, test as it } from 'vitest'; +import { convertPackageImports } from '../../../src/helpers/convert-imports.mjs'; + +it('should import amsmath when \\cfrac is present', () => { + const pks = convertPackageImports('\\cfrac'); + + expect(pks).toContain('amsmath'); +}); + +it('should import graphicx when <img is present', () => { + const pks = convertPackageImports('<img'); + + expect(pks).toContain('graphicx'); +}); + +it('should import amssymb when \\therefore is present', () => { + const pks = convertPackageImports('\\therefore'); + + expect(pks).toContain('amssymb'); +}); + +it('should import amssymb when <s> is present', () => { + const pks = convertPackageImports('<s>'); + + expect(pks).toContain('ulem'); +}); + +it('should import hyperref when </a> is present', () => { + const pks = convertPackageImports('</a>'); + + expect(pks).toContain('hyperref'); +}); + +it('should import listings when </code> is present', () => { + const pks = convertPackageImports('</code>'); + + expect(pks).toContain('listings'); +}); diff --git a/test/unit/helpers/convert-inline-element.mts b/test/unit/helpers/convert-inline-element.mts new file mode 100644 index 0000000..ccf1b57 --- /dev/null +++ b/test/unit/helpers/convert-inline-element.mts @@ -0,0 +1,136 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import * as Template from '../../../src/templates.mts'; +import { convertInlineElement } from '../../../src/helpers/convert-inline-element.mts'; +import * as convertPlainTextUtils from '../../../src/helpers/convert-plain-text.mts'; + +it('should handle pure text by calling the convertPlainText function', () => { + const convertPlainTextSpy = vi.spyOn(convertPlainTextUtils, 'convertPlainText'); + + const node = parseFragment('<span>test</span>'); + const converted = convertInlineElement(node.childNodes[0]); + + // Roundabout way to test this since spying on a direct function isnt doable nicely + expect(convertPlainTextSpy).toHaveBeenCalledWith('test', { + ignoreBreaks: true, + }); + expect(converted).toBe('test'); +}); + +it('should handle bold tags by calling the bold template', () => { + const templateSpy = vi.spyOn(Template, 'bold'); + + const nodes = [ + parseFragment('<span><b>test</b></span>'), + parseFragment('<span><strong>test</strong></span>'), + ]; + + nodes.forEach((n) => { + convertInlineElement(n.childNodes[0]); + expect(templateSpy).toHaveBeenCalledWith('test'); + }); +}); + +it('should handle italic tags by calling the italic template', () => { + const templateSpy = vi.spyOn(Template, 'italic'); + + const nodes = [ + parseFragment('<span><i>test</i></span>'), + parseFragment('<span><em>test</em></span>'), + ]; + + nodes.forEach((n) => { + convertInlineElement(n.childNodes[0]); + expect(templateSpy).toHaveBeenCalledWith('test'); + }); +}); + +it('should handle underline tags by calling the underline template', () => { + const templateSpy = vi.spyOn(Template, 'underline'); + + const node = parseFragment('<span><u>test</u></span>'); + + convertInlineElement(node.childNodes[0]); + + expect(templateSpy).toHaveBeenCalledWith('test'); +}); + +it('should handle strikethrough tags by calling the strikethrough template', () => { + const templateSpy = vi.spyOn(Template, 'strikethrough'); + + const node = parseFragment('<span><s>test</s></span>'); + + convertInlineElement(node.childNodes[0]); + + expect(templateSpy).toHaveBeenCalledWith('test'); +}); + +it('should handle subscript tags by calling the subscript template', () => { + const templateSpy = vi.spyOn(Template, 'subscript'); + + const node = parseFragment('<span><sub>test</sub></span>'); + + convertInlineElement(node.childNodes[0]); + + expect(templateSpy).toHaveBeenCalledWith('test'); +}); + +it('should handle superscript tags by calling the superscript template', () => { + const templateSpy = vi.spyOn(Template, 'superscript'); + + const node = parseFragment('<span><sup>test</sup></span>'); + + convertInlineElement(node.childNodes[0]); + + expect(templateSpy).toHaveBeenCalledWith('test'); +}); + +it('should handle anchor tags by calling the hyperlink template', () => { + const templateSpy = vi.spyOn(Template, 'hyperlink'); + + const node = parseFragment('<span><a href="url">test</a></span>'); + + convertInlineElement(node.childNodes[0]); + + expect(templateSpy).toHaveBeenCalledWith('test', 'url'); +}); + +it('should handle break tags by inserting double new lines', () => { + const node = parseFragment('<span><br>test</span>'); + + const converted = convertInlineElement(node.childNodes[0], { ignoreBreaks: false }); + + expect(converted).toBe('\n\ntest'); +}); + +it('should skip break tags if the ignoreBreaks option is passed', () => { + const node = parseFragment('<span><br>test</span>'); + + const converted = convertInlineElement(node.childNodes[0], { ignoreBreaks: true }); + + expect(converted).toBe(' test'); +}); + +it('should skip break tags by default', () => { + const node = parseFragment('<span><br>test</span>'); + + const converted = convertInlineElement(node.childNodes[0]); + + expect(converted).toBe(' test'); +}); + +it('should return an empty string if no tags are matched', () => { + const node = parseFragment('<span><unknown></unknown></span>'); + + const converted = convertInlineElement(node.childNodes[0]); + + expect(converted).toBe(''); +}); + +it('should handle multiple nested tags', () => { + const node = parseFragment('<span><b>One</b><span><i>Two</i></span></span>'); + + const converted = convertInlineElement(node.childNodes[0]); + + expect(converted).toBe('\\textbf{One}\\textit{Two}'); +}); diff --git a/test/unit/helpers/convert-list.mts b/test/unit/helpers/convert-list.mts new file mode 100644 index 0000000..0266bb9 --- /dev/null +++ b/test/unit/helpers/convert-list.mts @@ -0,0 +1,27 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import * as Template from '../../../src/templates.mts'; +import { convertList } from '../../../src/helpers/convert-list.mts'; +import * as convertElementUtils from '../../../src/helpers/convert-element.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should parse out the li element children from the node and convert its contents', async () => { + const convertElementSpy = vi.spyOn(convertElementUtils, 'convertElement'); + + const node = parseFragment('<ul><li>one</li><li>two</li><span>three</span></ul>'); + + const converted = await convertList(node.childNodes[0] as ElementNode); + + expect(convertElementSpy).toHaveBeenCalledTimes(2); + expect(converted).toMatch('\t\\item one\n\t\\item two'); +}); + +it('should use the item template for each of the converted li blocks', async () => { + const templateSpy = vi.spyOn(Template, 'item'); + + const node = parseFragment('<ul><li>one</li><li>two</li><span>three</span></ul>'); + + await convertList(node.childNodes[0] as ElementNode); + + expect(templateSpy).toHaveBeenCalledTimes(2); +}); diff --git a/test/unit/helpers/convert-ordered-list.mts b/test/unit/helpers/convert-ordered-list.mts new file mode 100644 index 0000000..9be63b0 --- /dev/null +++ b/test/unit/helpers/convert-ordered-list.mts @@ -0,0 +1,34 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import * as Template from '../../../src/templates.mts'; +import { convertOrderedList } from '../../../src/helpers/convert-ordered-list.mts'; +import * as convertListUtils from '../../../src/helpers/convert-list.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should parse out the li element children from the node using the convertList helper', async () => { + const convertListSpy = vi.spyOn(convertListUtils, 'convertList'); + + const node = parseFragment('<ol><li>one</li><li>two</li><span>three</span></ol>'); + + await convertOrderedList(node.childNodes[0] as ElementNode); + + expect(convertListSpy).toHaveBeenCalledWith(node.childNodes[0], {}); +}); + +it('should use the enumerate template for each of the converted li blocks', async () => { + const templateSpy = vi.spyOn(Template, 'enumerate'); + + const node = parseFragment('<ol><li>one</li><li>two</li><span>three</span></ol>'); + + await convertOrderedList(node.childNodes[0] as ElementNode); + + expect(templateSpy).toHaveBeenCalledWith; +}); + +it('should convert the list elements using enumerate environment', async () => { + const node = parseFragment('<ol><li>one</li><li>two</li><span>three</span></ol>'); + + const output = await convertOrderedList(node.childNodes[0] as ElementNode); + + expect(output).toMatch('\\begin{enumerate}\n\t\\item one\n\t\\item two\n\\end{enumerate}'); +}); diff --git a/test/unit/helpers/convert-paragraph.mts b/test/unit/helpers/convert-paragraph.mts new file mode 100644 index 0000000..1f191e9 --- /dev/null +++ b/test/unit/helpers/convert-paragraph.mts @@ -0,0 +1,50 @@ +import { expect, test as it } from 'vitest'; +import { convertParagraph } from '../../../src/helpers/convert-paragraph.mts'; +import { parseFragment } from 'parse5'; +import { ElementNode } from '../../../src/types.mts'; + +it('should convert eq wrappers \\[ wrapper instead of \\( when p tag only includes an equation', async () => { + const node = parseFragment('<p>\\(x = 5\\Omega\\)</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode); + + expect(output).toBe('\\[x = 5\\Omega\\]'); +}); + +it('should use the \\[ wrapper instead of $ when p tag only includes an equation', async () => { + const node = parseFragment('<p>$x = 5\\Omega$</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode); + + expect(output).toBe('\\[x = 5\\Omega\\]'); +}); + +it('should use the \\[ wrapper instead of \\( if skipWrappingEquations is true when p tag only includes an equation', async () => { + const node = parseFragment('<p>\\(x = 5\\Omega\\)</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode, { + skipWrappingEquations: true, + }); + + expect(output).toBe('\\(x = 5\\Omega\\)'); +}); + +it('should not use the \\[ wrapper instead of $ if skipWrappingEquations is true when p tag only includes an equation', async () => { + const node = parseFragment('<p>$x = 5\\Omega$</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode, { + skipWrappingEquations: true, + }); + + expect(output).toBe('$x = 5\\Omega$'); +}); + +it('should not modify equation wrappers in p tags with an equation and other content', async () => { + const node = parseFragment('<p>Some content $x = 5\\Omega$</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode); + + expect(output).toBe('Some content $x = 5\\Omega$'); +}); + +it('should not use the \\[ wrapper instead of $ if there is an unmatched $ in the equation when p tag only includes an equation', async () => { + const node = parseFragment('<p>$x = 5$$</p>'); + const output = convertParagraph(node.childNodes[0] as ElementNode); + + expect(output).toBe('$x = 5$$'); +}); diff --git a/test/unit/helpers/convert-plain-text.mts b/test/unit/helpers/convert-plain-text.mts new file mode 100644 index 0000000..9da2d95 --- /dev/null +++ b/test/unit/helpers/convert-plain-text.mts @@ -0,0 +1,94 @@ +import { expect, test as it } from 'vitest'; +import { convertPlainText } from '../../../src/helpers/convert-plain-text.mts'; + +it('should standardize line breaks by removing multiples return chatacters and tabs', () => { + // New line character + const output1 = convertPlainText('\n', { ignoreBreaks: false }); + + expect(output1).toBe('\n\n'); + + // Carrage character + const output2 = convertPlainText('\r', { ignoreBreaks: false }); + + expect(output2).toBe('\n\n'); + + // Multiple return chatacters + const output3 = convertPlainText('\r\n\r\n\n', { ignoreBreaks: false }); + + expect(output3).toBe('\n\n'); +}); + +it('should support skipping line break standardization by default', () => { + // New line character + const output1 = convertPlainText('\n'); + + expect(output1).toBe(''); + + // Carrage character + const output2 = convertPlainText('\r'); + + expect(output2).toBe(''); + + // Multiple return chatacters + const output3 = convertPlainText('\r\n\r\n\n'); + + expect(output3).toBe(''); +}); + +it('should remove tab characters', () => { + const output = convertPlainText('Styled\tText'); + + expect(output).toBe('StyledText'); +}); + +it('should escape special characters', () => { + const output = convertPlainText('% & # ~ < > |'); + + expect(output).toBe('\\% \\& \\# \\textasciitilde{} < > \\textbar{}'); +}); + +it('should not inlining math equations by default', () => { + const output = convertPlainText(String.raw`\(3+2\)`); + + expect(output).toBe(String.raw`\(3+2\)`); +}); + +it('should support inlining math equations through the $ latex character', () => { + const output = convertPlainText(String.raw`\(3+2\)`, { preferDollarInlineMath: true }); + + expect(output).toBe('$3+2$'); +}); + +it('should prefer $ eq wrappers if configuration is given', async () => { + const output = convertPlainText('Some content \\(x = 5\\Omega\\)', { + preferDollarInlineMath: true, + }); + + expect(output).toBe('Some content $x = 5\\Omega$'); +}); + +it('should handle eqs deep within text without tag wrapping', async () => { + const input = + 'This is some plain text \\(A,{\\rm{ }}B\\) and \\(C\\) with random equations \\(a,{\\rm{ }}b\\) and \\(c\\) \\((a < b < c)\\)'; + const output = convertPlainText(input, { preferDollarInlineMath: true }); + + expect(output).toBe( + 'This is some plain text $A,{\\rm{ }}B$ and $C$ with random equations $a,{\\rm{ }}b$ and $c$ $(a < b < c)$', + ); +}); + +// This was removed because it would be fail since we are allowing inline math in HTML. +it.skip('should escape `$`, `#`, `_`, `{`, `}`, `~`, `^`', async () => { + const input = 'Styled$Text #Text _Text {Text} ~Text ^Text'; + const output = convertPlainText(input); + + expect(output).toBe('Styled\\$Text \\#Text \\_Text \\{Text\\} \\~Text \\^Text'); +}); + +// Again, this was removed because we are allowing inline math in HTML. +it.skip('should escape `\\`', async () => { + const input = 'Styled\\Text'; + const output = convertPlainText(input); + + expect(output).toBe('Styled\\textbackslash{}Text'); +}); diff --git a/test/unit/helpers/convert-table-row.mts b/test/unit/helpers/convert-table-row.mts new file mode 100644 index 0000000..3636cbf --- /dev/null +++ b/test/unit/helpers/convert-table-row.mts @@ -0,0 +1,16 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import { convertTableRow } from '../../../src/helpers/convert-table-row.mts'; +import * as convertInlineUtils from '../../../src/helpers/convert-inline-element.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should only process td and th tags from the passed node', () => { + const convertInlineElementSpy = vi.spyOn(convertInlineUtils, 'convertInlineElement'); + + const node = parseFragment('<tr><th>title</th><td>cell</td><span>Test</span></tr>'); + + const output = convertTableRow(node.childNodes[0] as ElementNode); + + expect(convertInlineElementSpy).toBeCalledTimes(2); + expect(output).toBe('title & cell \\\\\n'); +}); diff --git a/test/unit/helpers/convert-table.mts b/test/unit/helpers/convert-table.mts new file mode 100644 index 0000000..e3abe1d --- /dev/null +++ b/test/unit/helpers/convert-table.mts @@ -0,0 +1,20 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import { convertTable } from '../../../src/helpers/convert-table.mts'; +import * as convertTableRowUtils from '../../../src/helpers/convert-table-row.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should only process tr tags from the passed node', () => { + const convertTableRowSpy = vi.spyOn(convertTableRowUtils, 'convertTableRow'); + + const node = parseFragment( + '<tbody><tr><th>title</th><td>cell</td><span>Test</span></tr></tbody>', + ); + + const output = convertTable(node.childNodes[0] as ElementNode); + + expect(convertTableRowSpy).toBeCalledTimes(1); + expect(output).toBe( + '\\begin{tabular}{|c|c|}\n\t\\hline\n\ttitle & cell \\\\\n\t\\hline\n\\end{tabular}', + ); +}); diff --git a/test/unit/helpers/convert-text.mts b/test/unit/helpers/convert-text.mts new file mode 100644 index 0000000..8b92a00 --- /dev/null +++ b/test/unit/helpers/convert-text.mts @@ -0,0 +1,143 @@ +import { expect, test as it, vi } from 'vitest'; +import * as parse5 from 'parse5'; +import * as Templates from '../../../src/templates.mts'; +import { convertText } from '../../../src/helpers/convert-text.mts'; +import * as convertElementUtils from '../../../src/helpers/convert-element.mts'; +import * as convertImportUtils from '../../../src/helpers/convert-imports.mts'; + +// TODO: Move into a __mocks__ directory +type MockedParse5 = { parseFragement(this: void): void }; + +vi.mock('parse5', async (getModule) => { + const original: MockedParse5 = await getModule(); + + return { + ...original, + parseFragement: vi.fn().mockImplementation(original.parseFragement), + }; +}); + +it('should parse the input html and convert to latex', async () => { + const parse5Spy = vi.spyOn(parse5, 'parseFragment'); + const convertElementSpy = vi.spyOn(convertElementUtils, 'convertElement'); + const html = `<body>Test</body>`; + const root = parse5.parseFragment(html); + const tex = await convertText(html, { includeDocumentWrapper: true }); + + expect(parse5Spy).toHaveBeenCalledWith(html); + expect(convertElementSpy).toHaveBeenCalledWith(root.childNodes[0], {}); + expect(tex).toBe('\\documentclass{article}\n\n\\begin{document}\n\n\nTest\n\n\n\\end{document}'); +}); + +it('should include a document wrapper if configured', async () => { + const beginDocumentTemplateSpy = vi.spyOn(Templates, 'beginDocument'); + const endDocumentTemplateSpy = vi.spyOn(Templates, 'endDocument'); + const html = `<body></body>`; + + await convertText(html, { includeDocumentWrapper: true }); + + expect(beginDocumentTemplateSpy).toHaveBeenCalled(); + expect(endDocumentTemplateSpy).toHaveBeenCalled(); +}); + +it('should not include a document wrapper by default', async () => { + const beginDocumentTemplateSpy = vi.spyOn(Templates, 'beginDocument'); + const endDocumentTemplateSpy = vi.spyOn(Templates, 'endDocument'); + const html = `<body></body>`; + + await convertText(html); + + expect(beginDocumentTemplateSpy).not.toHaveBeenCalled(); + expect(endDocumentTemplateSpy).not.toHaveBeenCalled(); +}); + +it('should support custom package imports', async () => { + const templateSpy = vi.spyOn(Templates, 'usePackages'); + const html = `<body></body>`; + + await convertText(html, { + includePackages: ['amsmath'], + includeDocumentWrapper: true, + }); + + expect(templateSpy).toBeCalledWith(['amsmath']); +}); + +it('should add known packages by default if matching tags are present within the input html and no custom packages are specified', async () => { + const templateSpy = vi.spyOn(Templates, 'usePackages'); + const convertPackageImportSpy = vi.spyOn(convertImportUtils, 'convertPackageImports'); + const html = `<body>\\cfrac</body>`; + + await convertText(html, { includeDocumentWrapper: true }); + + expect(convertPackageImportSpy).toBeCalledWith(html); + expect(templateSpy).toBeCalledWith(['amsmath']); +}); + +it('should support adding an author to the documentWrapper if passed', async () => { + const templateSpy = vi.spyOn(Templates, 'beginDocument'); + const html = `<body></body>`; + + await convertText(html, { includeDocumentWrapper: true, author: 'Takashi Kovacs' }); + + expect(templateSpy).toBeCalledWith({ + title: undefined, + includeDate: false, + author: 'Takashi Kovacs', + }); +}); + +it('should support adding a title to the documentWrapper if passed', async () => { + const templateSpy = vi.spyOn(Templates, 'beginDocument'); + const html = `<body></body>`; + + await convertText(html, { includeDocumentWrapper: true, title: 'Altered Carbon' }); + + expect(templateSpy).toBeCalledWith({ + title: 'Altered Carbon', + includeDate: false, + author: undefined, + }); +}); + +it('should support adding a the current date to the documentWrapper if the includeDate flag is passed', async () => { + const templateSpy = vi.spyOn(Templates, 'beginDocument'); + const html = `<body></body>`; + + await convertText(html, { includeDocumentWrapper: true, includeDate: true }); + + expect(templateSpy).toBeCalledWith({ title: undefined, includeDate: true, author: undefined }); +}); + +it('should support custom documentClasses', async () => { + const templateSpy = vi.spyOn(Templates, 'docClass'); + const html = `<body></body>`; + + await convertText(html, { + includeDocumentWrapper: true, + documentClass: 'fancydoc', + }); + + expect(templateSpy).toBeCalledWith('fancydoc'); +}); + +it('should convert simple tags with special chars', async () => { + const html = `<h1>Heading's</h1><section>Section's</section><p>Paragraph's</p>`; + const tex = await convertText(html); + + expect(tex).toBe("\\section*{\\centering{Heading's}}\n\nSection's\n\nParagraph's"); +}); + +it('should convert simple tags with embedded css', async () => { + const html = `<h1 style="margin:0px">Heading's</h1>`; + const tex = await convertText(html); + + expect(tex).toBe("\\section*{\\centering{Heading's}}"); +}); + +it('should convert simple tags with ignoring any attributes', async () => { + const html = `<h1 style="margin:0px" class="test" id="pgTitle">Heading's</h1>`; + const tex = await convertText(html); + + expect(tex).toBe("\\section*{\\centering{Heading's}}"); +}); diff --git a/test/unit/helpers/convert-unordered-list.mts b/test/unit/helpers/convert-unordered-list.mts new file mode 100644 index 0000000..de71ff8 --- /dev/null +++ b/test/unit/helpers/convert-unordered-list.mts @@ -0,0 +1,34 @@ +import { parseFragment } from 'parse5'; +import { expect, test as it, vi } from 'vitest'; +import * as Template from '../../../src/templates.mts'; +import { convertUnorderedList } from '../../../src/helpers/convert-unordered-list.mts'; +import * as convertListUtils from '../../../src/helpers/convert-list.mts'; +import { ElementNode } from '../../../src/types.mts'; + +it('should parse out the li element children from the node using the convertList helper', async () => { + const convertListSpy = vi.spyOn(convertListUtils, 'convertList'); + + const node = parseFragment('<ul><li>one</li><li>two</li><span>three</span></ul>'); + + await convertUnorderedList(node.childNodes[0] as ElementNode); + + expect(convertListSpy).toHaveBeenCalledWith(node.childNodes[0], {}); +}); + +it('should use the itemize template for each of the converted li blocks', async () => { + const templateSpy = vi.spyOn(Template, 'itemize'); + + const node = parseFragment('<ul><li>one</li><li>two</li><span>three</span></ul>'); + + await convertUnorderedList(node.childNodes[0] as ElementNode); + + expect(templateSpy).toHaveBeenCalledWith; +}); + +it('should convert the list elements using itemize environment', async () => { + const node = parseFragment('<ul><li>one</li><li>two</li><span>three</span></ul>'); + + const output = await convertUnorderedList(node.childNodes[0] as ElementNode); + + expect(output).toMatch('\\begin{itemize}\n\t\\item one\n\t\\item two\n\\end{itemize}'); +}); diff --git a/test/unit/templates.mts b/test/unit/templates.mts new file mode 100644 index 0000000..db46f2e --- /dev/null +++ b/test/unit/templates.mts @@ -0,0 +1,81 @@ +import { expect, describe, test as it } from 'vitest'; +import { latexSpecialCharacter } from '../../src/templates.mts'; + +describe('latexSpecialCharacter', () => { + it('should escape special character: "\\"', () => { + const input = '\\'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\textbackslash{}'); + }); + + it('should escape special character: "{"', () => { + const input = '{'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\{'); + }); + + it('should escape special character: "}"', () => { + const input = '}'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\}'); + }); + + it('should escape special character: "%"', () => { + const input = '%'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\%'); + }); + + it('should escape special character: "$"', () => { + const input = '$'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\$'); + }); + + it('should escape special character: "&"', () => { + const input = '&'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\&'); + }); + + it('should escape special character: "#"', () => { + const input = '#'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\#'); + }); + + it('should escape special character: "^"', () => { + const input = '^'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\^{}'); + }); + + it('should escape special character: "_"', () => { + const input = '_'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\_'); + }); + + it('should escape special character: "~"', () => { + const input = '~'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\textasciitilde{}'); + }); + + it('should escape special character: "|"', () => { + const input = '|'; + const output = latexSpecialCharacter(input); + + expect(output).toStrictEqual('\\textbar{}'); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d706b31 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "ESNext", + "noEmit": true, + "pretty": true, + "sourceMap": true, + "inlineSources": true, + "allowJs": true, + + "moduleResolution": "bundler", + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + + "strictPropertyInitialization": true, + "strictNullChecks": true, + "noImplicitAny": false, + "downlevelIteration": true, + "esModuleInterop": true, + + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + + "types": ["node"] + } +} diff --git a/vite.config.mts b/vite.config.mts new file mode 100644 index 0000000..e25fb3d --- /dev/null +++ b/vite.config.mts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['test/unit/**/*.?(c|m)[jt]s?(x)'], + coverage: { + enabled: true, + provider: 'istanbul', + }, + reporters: ['junit', 'json', 'verbose'], + outputFile: { + junit: './reports/junit-report.xml', + json: './reports/json-report.json', + }, + }, +});